Python面向?qū)ο箢惥帉懠?xì)節(jié)分析【類,方法,繼承,超類,接口等】
本文實例講述了Python面向?qū)ο箢惥帉懠夹g(shù)細(xì)節(jié)。分享給大家供大家參考,具體如下:
類代碼編寫細(xì)節(jié)
繼續(xù)學(xué)習(xí)類、方法和繼承。
class語句
以下是class語句的一般形式:
class <name>(superclass,...): data = value def method(self,...): self.member = value
在class語句內(nèi),任何賦值語句都會產(chǎn)生類屬性,而且還有特殊名稱方法重載運(yùn)算符。例如,名為__init__
的函數(shù)會在實例對象構(gòu)造時調(diào)用(如果定義過的話)。
例子
類是命名空間,也就是定義變量名(屬性)的工具。
1.就像函數(shù)一樣,class語句是本地作用域,由內(nèi)嵌的賦值語句建立的變量名,就存在于這個本地作用域內(nèi)。
2.就像模塊內(nèi)的變量名,在class語句內(nèi)賦值的變量名會變成類對象中的屬性。
因為class是復(fù)合語句,所以任何種類的語句都可位于其主體內(nèi):print、=、if、def等。當(dāng)class語句自身執(zhí)行時,class語句內(nèi)的所有語句都會執(zhí)行。在class語句內(nèi)賦值的變量名,會創(chuàng)建類屬性,而內(nèi)嵌的def則會創(chuàng)建類方法。
例如,把簡單的非函數(shù)的對象賦值給類屬性,就會產(chǎn)生數(shù)據(jù)屬性,由所有實例共享。
>>> class ShareData: spam = 42 >>> x = ShareData() >>> y = ShareData() >>> x.spam,y.spam (42, 42)
在這里,因為變量名spam是在class語句的頂層進(jìn)行賦值的,因此會附加在這個類中,從而為所有的實例共享。我們可通過類名稱修改它,或者是通過實例或類引用它。
>>> ShareData.spam = 99 >>> x.spam,y.spam,ShareData.spam (99, 99, 99)
這種類屬性可以用于管理貫穿所有實例的信息。例如,所產(chǎn)生的實例的數(shù)目的計數(shù)器。
現(xiàn)在,如果通過實例而不是類來給變量名spam賦值時,看看會發(fā)生什么:
>>> x.spam = 88 >>> x.spam,y.spam,ShareData.spam (88, 99, 99)
對實例的屬性進(jìn)行賦值運(yùn)算會在該實例內(nèi)創(chuàng)建或修改變量名,而不是在共享的類中。
對對象屬性進(jìn)行賦值總是會修改該對象,除此之外沒有其他的影響。例如,y.spam
會通過繼承而在類中查找,但是,對x.spam
進(jìn)行賦值運(yùn)算則會把該變量名附加在x本身上。
看下面這個例子,可以更容易理解這種行為,把相同的變量名儲存在兩個位置:
>>> class MixedNames: data = 'spam' def __init__(self,value): self.data = value def display(self): print(self.data,MixedNames.data)
當(dāng)創(chuàng)建這個類的實例的時候,變量名data會在構(gòu)造函數(shù)方法內(nèi)對self.data
進(jìn)行賦值運(yùn)算,從而把data附加到這些實例上。
>>> x = MixedNames(1) >>> y = MixedNames(2) >>> x.display(),y.display() 1 spam 2 spam (None, None)
【這里的(None,None)是調(diào)用display函數(shù)的返回值】
結(jié)果就是,data存在于兩個地方:在實例對象內(nèi)(由__init__
中的self.data
賦值運(yùn)算所創(chuàng)建)以及在實例繼承變量名的類中(由類中的data賦值運(yùn)算所創(chuàng)建)。類的display方法打印了這兩個版本,先以點(diǎn)號運(yùn)算得到self實例的屬性,然后才是類。
利用這些技術(shù)把屬性儲存在不同對象內(nèi),我們可以決定其可見范圍。附加在類上時,變量名是共享的;附加在實例上時,變量名是屬于每個實例的數(shù)據(jù),而不是共享的數(shù)據(jù)。
方法
方法即函數(shù)。方法在class中是由def語句創(chuàng)建的函數(shù)對象。從抽象的角度來看,方法替實例對象提供了要繼承的行為。從程序的角度看,方法與簡單函數(shù)的工作方式完全一致,只是有一個重要的差別:方法的第一個參數(shù)總是接收方法調(diào)用的隱性主體,也就是實例對象。
Python會自動把實例方法的調(diào)用對應(yīng)到類方法函數(shù)。如下所示,方法調(diào)用需要通過實例,就像這樣:
instance.method(args...)
這會自動翻譯成以下形式的類方法函數(shù)調(diào)用:
class.method(instance,args...)
class通過Python繼承搜索流程找出方法名稱所在之處。事實上,兩種調(diào)用形式在Python中都有效。
在類方法中,按慣例第一個參數(shù)通常都稱為self(嚴(yán)格來說,只有其位置重要,而不是它的名稱)。這個參數(shù)給方法提供了一個鉤子,從而返回調(diào)用的主體,也就是實例對象:因為類可以產(chǎn)生許多實例對象,所以需要這個參數(shù)來慣例每個實例彼此各不相同的數(shù)據(jù)。
例子
定義下面這個類:
>>> class NextClass: def printer(self,text): self.message = text print(self.message)
我們通過實例調(diào)用printer方法如下:
>>> x = NextClass() >>> x.printer('instance call') instance call >>> x.message 'instance call'
當(dāng)通過實例進(jìn)行點(diǎn)號運(yùn)算調(diào)用它時,printer會先通過繼承將其定位,然后它的self參數(shù)會自動賦值為實例對象(x)。text參數(shù)會獲得在調(diào)用時傳入的字符串('instance call')。注意:因為Python會自動傳遞第一個參數(shù)給self,實際上只需要傳遞一個參數(shù)。在printer中,變量名self是用于讀取或設(shè)置每個實例的數(shù)據(jù)的,因為self引用的是當(dāng)前正在處理的實例。
方法能通過實例或類本身兩種方法其中的任意一種進(jìn)行調(diào)用。例如,我們也可以通過類的名稱調(diào)用printer,只要明確地傳遞了一個實例給self參數(shù)。
>>> NextClass.printer(x,'class call')#Direct Class Call class call >>> x.message 'class call'
通過實例和類的調(diào)用具有相同的效果,只要在類形式中傳遞了相同的實例對象。實際上,在默認(rèn)情況下,如果嘗試不帶任何實例調(diào)用的方法時,就會得到出錯信息。
>>> NextClass.printer('bad call') Traceback (most recent call last): File "<pyshell#35>", line 1, in <module> NextClass.printer('bad call') TypeError: printer() missing 1 required positional argument: 'text'
調(diào)用超類構(gòu)造函數(shù)
在構(gòu)造時,Python會找出并且只調(diào)用一個__init__
。如果保證子類的構(gòu)造函數(shù)也會執(zhí)行超類構(gòu)造時的邏輯,一般都必須通過類明確地調(diào)用超類的__init__
方法。
class Super: def __init__(self,x): ...default code... class Sub(Super): def __init__(self,x,y): Super.__init__(self,x) ...custom code... I = Sub(1,2)
這種寫法便于維護(hù)代碼,之前也介紹過。這種方法擴(kuò)展了超類的方法,而不是完全取代了它。
類接口技術(shù)
擴(kuò)展只是一種與超類接口的方法。下面所示的specialize.py文件定義了多個類,示范了一些常用技巧。
Super:定義一個method函數(shù)以及在子類中期待一個動作的delegate。
Inheritor:沒有提供任何新的變量名,因此會獲得Super中定義的一切內(nèi)容。
Replacer:用自己的版本覆蓋Super的method
Extender:覆蓋并回調(diào)默認(rèn)method,從而定制Super的method
Provider:實現(xiàn)Super的delegate方法預(yù)期的action方法。
下面是這個文件:
class Super: def method(self): print('in Super.methon') def delegate(self): self.action() class Inheritor(Super): pass class Replacer(Super): def method(self): print('in Replacer.method') class Extender(Super): def method(self): print('starting Extender.method') Super.method(self) print('ending Extender.method') class Provider(Super): def action(self): print('in Provider.action') if __name__=='__main__': for klass in (Inheritor,Replacer,Extender): print('\n'+klass.__name__+'...') klass().method() print('\nProvider...') x = Provider() x.delegate()
執(zhí)行結(jié)果如下:
Inheritor...
in Super.methon
Replacer...
in Replacer.method
Extender...
starting Extender.method
in Super.methon
ending Extender.method
Provider...
in Provider.action
抽象超類
注意上例中的Provider類是如何工作的。當(dāng)通過Provider實例調(diào)用delegate方法時,有兩個獨(dú)立的繼承搜索會發(fā)生:
1.在最初的x.delegate
的調(diào)用中,Python會搜索Provider實例和它上層的對象,直到在Super中找到delegate的方法。實例x會像往常一樣傳遞給這個方法的self參數(shù)。
2.在Super.delegate
方法中,self.action
會對self以及它上層的對象啟動新的獨(dú)立繼承搜索。因為self指的是Provider實例,在Provider子類中就會找到action方法。
這種“填空式”的代碼結(jié)構(gòu)一般就是OOP的軟件框架。這個例子中的超類有時也稱作是抽象超類——也就是類的部分行為默認(rèn)是由其子類所提供的。如果預(yù)期的方法沒有在子類中定義,當(dāng)繼承搜索失敗時,Python會引發(fā)未定義變量名的異常。
更多關(guān)于Python相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Python面向?qū)ο蟪绦蛟O(shè)計入門與進(jìn)階教程》、《Python數(shù)據(jù)結(jié)構(gòu)與算法教程》、《Python函數(shù)使用技巧總結(jié)》、《Python字符串操作技巧匯總》、《Python編碼操作技巧總結(jié)》及《Python入門與進(jìn)階經(jīng)典教程》
希望本文所述對大家Python程序設(shè)計有所幫助。
相關(guān)文章
使用Python實現(xiàn)下載網(wǎng)易云音樂的高清MV
本文給大家分享的是一則使用Python實現(xiàn)下載網(wǎng)易云音樂中高清MV的代碼,本人新手,沒有做特別的功能,僅僅是直接循環(huán)了MV的id,小伙伴們可以自己擴(kuò)展下。2015-03-03關(guān)于Python連接Cassandra容器進(jìn)行查詢的問題
這篇文章主要介紹了Python連接Cassandra容器進(jìn)行查詢的問題,問題的關(guān)鍵在于尋找到Cassandra的9042端口,從而獲取數(shù)據(jù),具有內(nèi)容詳情跟隨小編一起看看吧2021-11-11