|
不光是Python,大多數(shù)面向?qū)ο缶幊陶Z(yǔ)言(諸如C++、Java等)都具備3個(gè)典型特征,即封裝、繼承和多態(tài)。其中,本節(jié)重點(diǎn)講解Python類的封裝特性,繼承和多態(tài)會(huì)在后續(xù)章節(jié)給大家做詳細(xì)講解。
簡(jiǎn)單的理解封裝(Encapsulation),即在設(shè)計(jì)類時(shí),刻意地將一些屬性和方法隱藏在類的內(nèi)部,這樣在使用此類時(shí),將無(wú)法直接以“類對(duì)象.屬性名”(或者“類對(duì)象.方法名(參數(shù))”)的形式調(diào)用這些屬性(或方法),而只能用未隱藏的類方法間接操作這些隱藏的屬性和方法。 就好比使用電腦,我們只需要學(xué)會(huì)如何使用鍵盤和鼠標(biāo)就可以了,不用關(guān)心內(nèi)部是怎么實(shí)現(xiàn)的,因?yàn)槟鞘巧a(chǎn)和設(shè)計(jì)人員該操心的。 注意,封裝絕不是將類中所有的方法都隱藏起來(lái),一定要留一些像鍵盤、鼠標(biāo)這樣可供外界使用的類方法。 那么,類為什么要進(jìn)行封裝,這樣做有什么好處呢? 首先,封裝機(jī)制保證了類內(nèi)部數(shù)據(jù)結(jié)構(gòu)的完整性,因?yàn)槭褂妙惖挠脩魺o(wú)法直接看到類中的數(shù)據(jù)結(jié)構(gòu),只能使用類允許公開(kāi)的數(shù)據(jù),很好地避免了外部對(duì)內(nèi)部數(shù)據(jù)的影響,提高了程序的可維護(hù)性。 除此之外,對(duì)一個(gè)類實(shí)現(xiàn)良好的封裝,用戶只能借助暴露出來(lái)的類方法來(lái)訪問(wèn)數(shù)據(jù),我們只需要在這些暴露的方法中加入適當(dāng)?shù)目刂七壿?,即可輕松實(shí)現(xiàn)用戶對(duì)類中屬性或方法的不合理操作。 并且,對(duì)類進(jìn)行良好的封裝,還可以提高代碼的復(fù)用性。 Python類如何進(jìn)行封裝? 和其它面向?qū)ο蟮木幊陶Z(yǔ)言(如C++、Java)不同,Python類中的變量和函數(shù),不是公有的(類似public屬性),就是私有的(類似private),這2種屬性的區(qū)別如下: public:公有屬性的類變量和類函數(shù),在類的外部、類內(nèi)部以及子類(后續(xù)講繼承特性時(shí)會(huì)做詳細(xì)介紹)中,都可以正常訪問(wèn); private:私有屬性的類變量和類函數(shù),只能在本類內(nèi)部使用,類的外部以及子類都無(wú)法使用。 但是,Python并沒(méi)有提供public、private這些修飾符。為了實(shí)現(xiàn)類的封裝,Python采取了下面的方法: 默認(rèn)情況下,Python類中的變量和方法都是公有(public)的,它們的名稱前都沒(méi)有下劃線(_); 如果類中的變量和函數(shù),其名稱以雙下劃線“__”開(kāi)頭,則該變量(函數(shù))為私有變量(私有函數(shù)),其屬性等同于private。 除此之外,還可以定義以單下劃線“_”開(kāi)頭的類屬性或者類方法(例如_name、_display(self)),這種類屬性和類方法通常被視為私有屬性和私有方法,雖然它們也能通過(guò)類對(duì)象正常訪問(wèn),但這是一種約定俗稱的用法,初學(xué)者一定要遵守。 注意,Python類中還有以雙下劃線開(kāi)頭和結(jié)尾的類方法(例如類的構(gòu)造函數(shù)__init__(self)),這些都是Python內(nèi)部定義的,用于Python內(nèi)部調(diào)用。我們自己定義類屬性或者類方法時(shí),不要使用這種格式。 例如,如下程序示范了Python的封裝機(jī)制: class CLanguage :
def setname(self, name):
if len(name) < 3: raise ValueError('名稱長(zhǎng)度必須大于3!')
self.__name = name def getname(self):
return self.__name #為 name 配置 setter 和 getter 方法
name = property(getname, setname) def setadd(self, add):
if add.startswith("http://"):
self.__add = add else: raise ValueError('地址必須以 http:// 開(kāi)頭')
def getadd(self):
return self.__add
#為 add 配置 setter 和 getter 方法
add = property(getadd, setadd) #定義個(gè)私有方法
def __display(self):
print(self.__name,self.__add)
clang = CLanguage()
clang.name = "開(kāi)課吧廣場(chǎng)"clang.add = "https://topic./"print(clang.name)
print(clang.add)123456789101112131415161718192021222324252627復(fù)制代碼類型:[python]程序運(yùn)行結(jié)果為: 開(kāi)課吧廣場(chǎng) https://topic./12復(fù)制代碼類型:[python] 上面程序中,CLanguage將name和add屬性都隱藏了起來(lái),但同時(shí)也提供了可操作它們的“窗口”,也就是各自的setter和getter方法,這些方法都是公有(public)的。 不僅如此,以add屬性的setadd()方法為例,通過(guò)在該方法內(nèi)部添加控制邏輯,即通過(guò)調(diào)用startswith()方法,控制用戶輸入的地址必須以“http://”開(kāi)頭,否則程序?qū)?huì)執(zhí)行raise語(yǔ)句拋出ValueError異常。 有關(guān)raise的具體用法,后續(xù)章節(jié)會(huì)做詳細(xì)的講解,這里可簡(jiǎn)單理解成,如果用戶輸入不規(guī)范,程序?qū)?huì)報(bào)錯(cuò)。 通過(guò)此程序的運(yùn)行邏輯不難看出,通過(guò)對(duì)CLanguage類進(jìn)行良好的封裝,使得用戶僅能通過(guò)暴露的setter()和getter()方法操作name和add屬性,而通過(guò)對(duì)setname()和setadd()方法進(jìn)行適當(dāng)?shù)脑O(shè)計(jì),可以避免用戶對(duì)類中屬性的不合理操作,從而提高了類的可維護(hù)性和安全性。 細(xì)心的讀者可能還發(fā)現(xiàn),CLanguage類中還有一個(gè)__display()方法,由于該類方法為私有(private)方法,且該類沒(méi)有提供操作該私有方法的“窗口”,因此我們無(wú)法在類的外部使用它。換句話說(shuō),如下調(diào)用__display()方法是不可行的: #嘗試調(diào)用私有的 display() 方法clang.__display()12復(fù)制代碼類型:[python] 這會(huì)導(dǎo)致如下錯(cuò)誤: Traceback (most recent call last): File "D:\python3.6\1.py", line 33, in <module> clang.__display() AttributeError: 'CLanguage' object has no attribute '__display' |
|
|
來(lái)自: 碼農(nóng)9527 > 《Python》