文章目錄
第一節:關於類
面向對象
- 面向對象
之前我們介紹過函數,函數是對程序語句的封裝與複用;
類是則是對變量
和函數
的封裝和複用,封裝有機關聯的變量和函數爲類,變量和函數,稱爲類的屬性
和方法
;
由於類比函數的封裝又提高了一個層次,因此複用性也得到進一步提升;(試想一下維護100個函數直觀容易,還是維護5個類直觀容易呢?)
面向過程的編程是以函數
爲核心的,而面向對象的編程是以類
爲核心的,一切功能的實現,都是通過創建一個司職該功能的類的實例,進而調用其方法去予以實現的;
以類爲核心的、面向對象的編程,提高了代碼的模塊化程度,便於大規模協作的開展;
在面向對象的程序開發(Object-Oriented-Programming或OOP)中,架構師的工作,往往只是模塊拆分、接口定義、實例組裝,類內部的具體方法接口的實現,則交由其他人去完成;
現如今的高級語言,基本都是面向對象的;
面向對象的三大特性:封裝
、繼承
、多態
;
另一種提法是四大特性,即三大特性的基礎上,再加上一個抽象
;
-
封裝
封裝就是將常用的代碼段封裝爲函數,常用的函數封裝爲類,常用的類封裝爲模塊與類庫;
封裝提高了代碼的可維護性和複用性,同時也更利於開源與傳播;
封裝性催生了模塊化,便於大規模協作開發的開展; -
繼承
正如自然界中,動物=>人=>程序員的關係,人是動物類的一個分支,程序員是人的一個分支,在編程中,我們可以通過繼承來表達這樣的關係;
動物類是人類的父類(又叫超類),人是程序員的父類;
動物類的共同特徵,如都有生命、都會新陳代謝、都會死亡等等,在定義人這個類時,是無需重複聲明的,這樣就在一層層的繼承中,節省了大量的代碼;
有繼承就有發展,否則繼承就沒有意義;【編程中的繼承】
在編程中,發展體現爲:
①在父類的基礎上增加新的屬性與方法;
②重寫(或者叫覆寫、覆蓋)父類方法;
對父類方法的覆寫,又可以分爲【顛覆式】和【改良式】兩種;
【顛覆式】覆寫是指子類全盤否定父類方法實現,由子類自己做一個全新的實現;
【改良式】覆寫是指子類先將父類的實現拿過來,再進行新的拓展; -
多態
在繼承的基礎上,一個父類會有不同的子類實現,如戰士父類可以有騎兵、步兵、弓弩手等不同子類;
多態,即【一個父類可以有多種不同的子類形態】;
【多態的共性與個性】
在多態中,同源子類之間,既存在共性,又存在個性,共性與個性各有其用處;
例如騎兵、步兵、弓弩手都是戰士的子類,因此他們都有進攻方法與防守方法,這就是【共性】;
而他們的具體進攻方法各自有不同的實現,騎兵衝鋒、步兵肉搏、弓弩手射箭,這就是【個性】;
在一支由不同兵種組成的軍隊中(即戰士實例的集合),當總司令下達全體進攻的命令時,不同兵種做何種具體形式的進攻(個性)是不重要的,重要的是共性;
當司令想要採用一些細膩的戰術時,比如先進行一輪齊射,再由騎兵進行一輪踩踏,最後上步兵打掃戰場,此時不同兵種的差異化進攻方式則展現其價值,此時個性變得重要;
共性是由父類所帶來的,個性是由子類覆寫所帶來的;
-
抽象
在繼承和多態中,如果父類不對某個方法做任何實現,只是留白,具體的實現交由子類自己去完成,這時我們稱該方法是抽象的;
如果一個父類中的所有方法都是抽象的,我們就稱該類爲一個【接口】;
抽象是一種藝術,架構師就是這種藝術的玩弄者;
架構師所做的工作,就是拆分模塊,定義接口,完成預組裝,形成一具沒有血肉的架,然後將填充的工作下放到團隊中的不同程序員,填充完成之日即是項目大廈落成之時;
類的封裝
例:
-
封裝一個人的類Person,需求如下:
1、封裝以下屬性:姓名、年齡、存款
2、封裝自我介紹方法,陳述以上屬性
3、創建一個人,設置其基本信息
4、打印此人信息
5、令此人進行自我介紹
# 封裝一個Person類,將與人有關的屬性、方法組合在一起,以便將來複用
class Person:
# 屬性定義和默認值
name = "林阿華"
age = 20
rmb = 50
# 構造方法:外界創建類的實例時會調用
# 構造方法是初始化實例屬性的最佳時機
def __init__(self,name,age,rmb):
print("__init__的方法被調用了")
self.name = name
self.age = age
self.rmb = rmb
# 自我介紹方法
# self = 類的實例
def tell(self):
print("我是%s,我%d歲了,我有存款%.2f萬元"%(self.name,self.age,self.rmb))
- 創建實例p,並調用Person的tell()方法
# 創建Person類的實例
p = Person("易阿天",60,500)
# 調用實例的tell方法
p.tell()
執行結果:
注意將Person的屬性和方法使用一個
標準制表符
縮進在Person的類定義以內;
“_ init _”
是類的構造方法,用於創建類的實例,左右各有兩個下劃線;
使用PyCharm輸入完def __init時系統彈出提示,IDE會自動完成方法的定義;
每個方法在定義時,系統會自動加上一個self
參數在第一個參數位,這個參數代表將來創建的實例本身;
再調用方法時,self
是不必親自傳入的,self是系統用來標識實例本身的;
構造方法的調用形式爲:Person(self以外的其它參數)
;
類的私有成員
【成員】就是指類的
屬性
和方法
;
【私有】,即不能再類的外界進行訪問;
目的是爲了保障安全
,如涉及隱私的屬性、核心方法實現等;
例:
- 封裝一個人的類Person,需求如下:
1、創建一個Person類,添加存款信息
2、保護存款信息,將其設置爲私有
3、爲存款信息添加保護,使其不能被直接訪問
4、增加設置密碼功能 ·增加存款查詢功能
5、只有輸入密碼正確的情況下才能查詢存款信息
class Person:
# 普通屬性與私有屬性
name = "林阿華"
age = 20
__rmb = 1000 #(須通過公有方法來訪問)
# 私有方法:設置存款
def __setrmb(self,rmb):
self.__rmb = rmb
# 通過普通方法訪問私有方法進行存款設置
def setrmb(self,rmb):
pwd = input("請輸入設置密碼:")
if (pwd == "123456"):
self.__setrmb(rmb)
else:
print("您沒有權限")
# 公開一個普通方法,共外界訪問私有屬性self.__rmb
def getrmb(self):
pwd = input("請輸入查詢密碼:")
if (pwd == "123456"):
return self.__rmb
else:
return "您沒有訪問權限"
# 普通方法
def tell(self):
print("大家好,我是%s"%(self.name))
- 創建Person實例,並通過公有方法訪問私有成員
p = Person()
#通過實例訪問類的普通屬性
print(p.name)
print(p.age)
# 私有成員不能被直接訪問
# print(p.__rmb) # AttributeError: 'Person' object has no attribute '__rmb'
#通過實例訪問類的普通方法
p.tell()
#通過普通方法訪問私有屬性
rmb = p.getrmb()
print("我的存款是:",rmb)
# 通過普通方法訪問私有方法
p.setrmb(500)
rmb = p.getrmb()
print("我的存款是:",rmb)
執行結果:
- 注意的幾個問題
1、代碼中的__rmb
屬性、__setrmb
方法都是私有的,在類的外部是無法p.__rmb
進行直接訪問的;
2、任何前置兩個下劃線的成員(屬性與方法)都是私有的,只能在類的內部進行訪問;
外界訪問私有成員的方法是,使用公有方法對外界提供私有成員訪問接口
,但在內部先行進行權限校驗,如輸入密碼等,如本例中的setrmb
方法和getrmb
方法;