新聞中心
在現(xiàn)代編程世界中,面向?qū)ο缶幊?OOP)語(yǔ)言在改變軟件開(kāi)發(fā)中的設(shè)計(jì)和實(shí)現(xiàn)模式方面發(fā)揮了進(jìn)化作用。作為OOP家族的重要成員,Python在過(guò)去10年左右逐漸流行起來(lái)。與其他OOP語(yǔ)言一樣,Python圍繞大量不同的對(duì)象操作其數(shù)據(jù),包括模塊、類(lèi)和函數(shù)。

創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站建設(shè)、做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿(mǎn)足客戶(hù)于互聯(lián)網(wǎng)時(shí)代的江岸網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
如果您有任何OOP語(yǔ)言的編程經(jīng)驗(yàn),您應(yīng)該知道所有對(duì)象都有其內(nèi)部特征數(shù)據(jù),稱(chēng)為字段、屬性或?qū)傩?。在Python中,這些對(duì)象綁定的特征數(shù)據(jù)通常稱(chēng)為屬性。在本文中,我將特別在自定義類(lèi)的上下文中討論它們。
[[343460]]
1. 類(lèi)屬性
為了更好地管理項(xiàng)目中的數(shù)據(jù),我們經(jīng)常需要?jiǎng)?chuàng)建自定義類(lèi)。在Python中,類(lèi)也是對(duì)象,這意味著它們可以有自己的屬性。讓我們看一個(gè)例子。
- >>> class Dog:
- ... genus = "Canis"
- ... family = "Canidae"
- ...
- >>> Dog.genus
- 'Canis'
- >>> Dog.family
- 'Canidae'
- >>> dir(Dog)
- ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
- '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
- '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
- '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
- 'family', 'genus']
如上所示,我們聲明了一個(gè)名為Dog的類(lèi)。因?yàn)樗械墓范紝儆谌?lèi)屬和犬科家族,所以我們創(chuàng)建了兩個(gè)類(lèi)屬性,分別命名為屬和科來(lái)存儲(chǔ)這兩條信息。如您所見(jiàn),我們可以直接使用類(lèi)來(lái)訪(fǎng)問(wèn)這些屬性。我們可以使用函數(shù)dir來(lái)顯示狗的屬性列表,其中包括家族和屬。
這些定義為類(lèi)級(jí)別的屬性稱(chēng)為類(lèi)屬性,類(lèi)可以直接檢索它們。但是,與其他OOP語(yǔ)言不同,Python中的實(shí)例對(duì)象也可以直接訪(fǎng)問(wèn)這些類(lèi)屬性,如下面的代碼片段所示。
- >>> Dog().genus
- 'Canis'
- '>>> Dog().family
- 'Canidae'
2. 實(shí)例屬性
通過(guò)自定義類(lèi),我們還可以為實(shí)例對(duì)象設(shè)置屬性。這些屬性稱(chēng)為實(shí)例屬性,這意味著它們是特定于實(shí)例的數(shù)據(jù)。讓我們繼續(xù)狗類(lèi)。
- >>> class Dog:
- ... genus = "Canis"
- ... family = "Canidae"
- ...
- ... def __init__(self, breed, name):
- ... self.breed = breed
- ... self.name = name
- ...
在上面的代碼中,我們定義了__init__函數(shù),它將作為創(chuàng)建一個(gè)新的Dog實(shí)例的構(gòu)造方法。第一個(gè)參數(shù)self引用了我們正在創(chuàng)建的實(shí)例。在實(shí)例化期間(即創(chuàng)建新實(shí)例),我們將為新實(shí)例對(duì)象分配品種和名稱(chēng)信息,這些屬性將成為實(shí)例特征的一部分,如下所示。
- >>> dog = Dog("Rottweiler", "Ada")
- >>> dog.name
- 'Ada'
- >>> dog.breed
- 'Rottweiler'
需要注意的一點(diǎn)是,我們可以為具有與class屬性相同的屬性的實(shí)例賦值。在這種情況下,當(dāng)您檢索實(shí)例的這個(gè)屬性時(shí),將不會(huì)檢索class屬性。換句話(huà)說(shuō),當(dāng)您使用一個(gè)實(shí)例對(duì)象來(lái)檢索class屬性時(shí),Python將首先檢查實(shí)例本身是否有一個(gè)用相同名稱(chēng)設(shè)置的屬性。如果沒(méi)有,Python將使用class屬性作為回退。此外,設(shè)置一個(gè)實(shí)例的屬性不會(huì)影響同名類(lèi)的屬性。讓我們?cè)谙旅娴拇a片段中看看這些特征。
- >>> dog.genus = "Felis"
- >>> dog.genus
- 'Felis'
- >>> Dog('Poodle', 'Cutie').genus
- 'Canis'
3. 函數(shù)作為屬性
在Python中,一切都是對(duì)象,前面我已經(jīng)提到類(lèi)是對(duì)象。此外,函數(shù)是Python對(duì)象。在類(lèi)中,我們可以定義函數(shù),通常稱(chēng)為方法。根據(jù)使用這些函數(shù)的方式,我們可以將它們進(jìn)一步分類(lèi)為類(lèi)方法、靜態(tài)方法和實(shí)例方法。在這里,理解這些差異并不是必須的。
盡管某些OOP語(yǔ)言將屬性(或?qū)傩?和函數(shù)視為不同的實(shí)體,但Python將這些方法(函數(shù))視為類(lèi)的屬性——與我們前面定義的類(lèi)屬性沒(méi)有太大區(qū)別。讓我們用上面提到的三種方法來(lái)更新Dog類(lèi):類(lèi)方法、靜態(tài)方法和實(shí)例方法,如下所示。
- >>> class Dog:
- ... genus = "Canis"
- ... family = "Canidae"
- ...
- ... def __init__(self, breed, name):
- ... self.breed = breed
- ... self.name = name
- ...
- ... @classmethod
- ... def from_tag(cls, tag_info):
- ... breed = tag_info["breed"]
- ... name = tag_info["name"]
- ... return cls(breed, name)
- ...
- ... @staticmethod
- ... def can_bark():
- ... print("Yes. All dogs can bark.")
- ...
- ... def bark(self):
- ... print("The dog is barking.")
- ...
對(duì)于更新后的類(lèi),我們可以使用函數(shù)dir檢查類(lèi)的屬性列表。如下所示,類(lèi)方法和靜態(tài)方法都包含在列表中。
- >>> dir(Dog)
- ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
- '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
- '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
- '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
- 'bark', 'can_bark', 'family', 'from_tag', 'genus']
然而,有一件事可能會(huì)讓一些人感到驚訝,那就是該列表中包含了實(shí)例方法bark。我們知道,實(shí)例方法是那些由實(shí)例對(duì)象調(diào)用的函數(shù),因此有些人可能認(rèn)為這些實(shí)例方法應(yīng)該綁定到所有單獨(dú)的實(shí)例。然而,在Python中卻不是這樣。在解釋實(shí)例方法如何工作之前,讓我們先看看下面的代碼。
- >>> dog = Dog("Rottweiler", "Ada")
- >>> dog.bark()
- The dog is barking.
- >>> Dog.bark(dog)
- The dog is barking.
如上所示,我們首先創(chuàng)建了Dog類(lèi)的一個(gè)實(shí)例。與其他OOP語(yǔ)言一樣,實(shí)例對(duì)象可以直接調(diào)用實(shí)例方法bark。然而,Python與其他語(yǔ)言的不同之處在于,實(shí)例方法的調(diào)用是通過(guò)類(lèi)來(lái)操作的,通過(guò)傳遞實(shí)例作為參數(shù)來(lái)調(diào)用定義的函數(shù)(即,dog .bark(dog))。換句話(huà)說(shuō),instance.inst_method()在本質(zhì)上與Python中的Class.inst_method(instance)相同。
之所以可以這樣做,是因?yàn)镈og類(lèi)“擁有”實(shí)例方法,這是一種節(jié)省內(nèi)存的機(jī)制,因?yàn)镻ython不需要為每個(gè)實(shí)例對(duì)象創(chuàng)建單獨(dú)的函數(shù)副本。相反,當(dāng)一個(gè)實(shí)例調(diào)用一個(gè)實(shí)例方法時(shí),Python將調(diào)用委托給類(lèi),該類(lèi)將通過(guò)傳遞實(shí)例調(diào)用相應(yīng)的函數(shù)(它將被設(shè)置為已定義函數(shù)中的self參數(shù))。
4. 私有屬性
如果您有OOP的經(jīng)驗(yàn),就不應(yīng)該不熟悉訪(fǎng)問(wèn)修飾符的存在,比如public、private和protected。這些修飾符限制了可以訪(fǎng)問(wèn)修改的屬性和函數(shù)的范圍。然而,您很少在Python中聽(tīng)到這樣的討論。實(shí)際上,如果借用OOP中的術(shù)語(yǔ),所有Python屬性都是公共的。如上所示,在類(lèi)和實(shí)例可以訪(fǎng)問(wèn)的地方,類(lèi)和實(shí)例屬性都可以自由訪(fǎng)問(wèn)。因此,嚴(yán)格地說(shuō),Python中沒(méi)有真正的私有或受保護(hù)的屬性(后面將討論)。我們只是類(lèi)比地使用這些術(shù)語(yǔ),以便來(lái)自其他OOP背景的程序員更容易理解相關(guān)的編碼約定(是的,只是一種約定,沒(méi)有作為真正的訪(fǎng)問(wèn)控制加以加強(qiáng))。
讓我們首先討論一下如何在Python中定義“私有”屬性。慣例是用兩個(gè)前導(dǎo)下劃線(xiàn)命名這些屬性,并且不超過(guò)一個(gè)后引下劃線(xiàn)。考慮下面更新過(guò)的Dog類(lèi)的示例—為了簡(jiǎn)單起見(jiàn),我們省略了前面定義的其他屬性。
- >>> class Dog:
- ... def __init__(self, breed, name):
- ... self.breed = breed
- ... self.name = name
- ... self.__tag = f"{name} | {breed}"
- ...
- >>> dog = Dog("Rottweiler", "Ada")
- >>> dog.name
- 'Ada'
- >>> dog.__tag
- Traceback (most recent call last):
- File "
", line 1, in - AttributeError: 'Dog' object has no attribute '__tag'
在上面的更新之后,Dog實(shí)例將擁有一個(gè)名為tag的私有屬性,正如其名稱(chēng)所示。實(shí)例對(duì)象仍然可以像以前一樣訪(fǎng)問(wèn)它的其他屬性(例如,名稱(chēng))。然而,實(shí)例不能訪(fǎng)問(wèn)私有屬性剩余的標(biāo)記,這可能是我們所期望的。實(shí)際上,這種對(duì)訪(fǎng)問(wèn)這些屬性的限制正是它們被稱(chēng)為“私有”屬性的原因。但它是怎么發(fā)生的,在引擎蓋下?畢竟,我前面提到過(guò),所有Python屬性在默認(rèn)情況下都是公共的。下面將向您展示Python如何實(shí)現(xiàn)“私有”屬性。
- >>> dog.__dict__
- {'breed': 'Rottweiler', 'name': 'Ada', '_Dog__tag': 'Ada | Rottweiler'}
- >>> dog._Dog__tag
- 'Ada | Rottweiler'
__dict__特殊方法(也稱(chēng)為dunder方法,在名稱(chēng)前后都有雙下劃線(xiàn))能夠顯示對(duì)象的字典表示。具體來(lái)說(shuō),字典中的鍵-值對(duì)是對(duì)象的屬性及其值。正如我們所看到的,除了bread和name屬性之外,還有一個(gè)名為_(kāi)dog__tag標(biāo)記的屬性。這個(gè)屬性正是私有屬性__tag通過(guò)一個(gè)稱(chēng)為mangling的過(guò)程與對(duì)象關(guān)聯(lián)的方式。
具體來(lái)說(shuō),mangling或name mangling是使用_ClassName作為私有屬性的前綴,這樣我們就人為地創(chuàng)建了對(duì)這些“私有”屬性的訪(fǎng)問(wèn)限制。但是,如果我們確實(shí)想檢索任何私有屬性,我們?nèi)匀豢梢允褂帽黄茐牡拿Q(chēng)訪(fǎng)問(wèn)它,就像我們?cè)诖a片段中使用_dog__標(biāo)記所做的那樣。
5. 受保護(hù)的屬性
在上一節(jié)中,我們討論了私有屬性,但是受保護(hù)的屬性呢?Python中與受保護(hù)屬性對(duì)應(yīng)的屬性名稱(chēng)只有一個(gè)下劃線(xiàn)。不像雙下劃線(xiàn)會(huì)導(dǎo)致混亂,單下劃線(xiàn)前綴不會(huì)改變Python解釋器處理這些屬性的方式——它只是Python編程世界的一個(gè)慣例,表示他們(例如,編碼器)不希望你訪(fǎng)問(wèn)這些屬性。但是,如果你堅(jiān)持要訪(fǎng)問(wèn)它們,你仍然可以這樣做。讓我們看看下面的代碼。
- >>> class Dog:
- ... def __init__(self, breed, name):
- ... self.breed = breed
- ... self.name = name
- ... self.__tag = f"{name} | {breed}"
- ... self._nickname = name[0]
我們通過(guò)創(chuàng)建一個(gè)名為_(kāi)nickname的實(shí)例屬性來(lái)更新類(lèi)Dog。正如其名稱(chēng)使用下劃線(xiàn)前綴所表明的那樣,按照約定,它被認(rèn)為是一個(gè)“受保護(hù)”的屬性。我們?nèi)匀豢梢詫⑦@些受保護(hù)的屬性作為其他“公共”屬性來(lái)訪(fǎng)問(wèn),但是一些ide或Python編輯器不會(huì)為這些非公共屬性提供提示(例如,自動(dòng)完成提示)。有關(guān)這些使用Jupyter筆記本的例子,請(qǐng)參見(jiàn)屏幕截圖。
如果我們使用模塊而不是類(lèi),就像我們?cè)谶@里所做的那樣,當(dāng)我們使用from _module import *導(dǎo)入模塊時(shí),帶有下劃線(xiàn)前綴的名稱(chēng)將不會(huì)被導(dǎo)入,從而提供了一種機(jī)制來(lái)限制對(duì)這些“受保護(hù)的”屬性的訪(fǎng)問(wèn)。
當(dāng)前名稱(chēng):Python中的高階概念屬性:五個(gè)你應(yīng)該搞明白的知識(shí)點(diǎn)
網(wǎng)頁(yè)路徑:http://www.dlmjj.cn/article/djjpcgj.html


咨詢(xún)
建站咨詢(xún)
