前言:
本篇相關(guān)內(nèi)容分為3篇多態(tài)、繼承、封裝,這篇為第二篇 繼承。
Content:
- 繼承
1. 什么是繼承,繼承的作用和常用狀態(tài)?
2. python的多繼承、instance和type?
3. python中的super函數(shù)
4. python的MRO查找機(jī)制來對應(yīng)多繼承和super
5. python的抽象基類
6. django等大大框架和python源碼中最常用的Mixin模式多繼承實例
?(下篇
- 封裝
1.數(shù)據(jù)封裝和私有屬性
2. 類變量和實例變量(對象變量)
3. 類屬性和實例屬性得查找順序(MRO)
4. 靜態(tài)方法 類方法和對象方法使用以及參數(shù)
5. python的接口和自省機(jī)制
6. 上下文管理器
?)
?
一 繼承
1.什么是繼承?繼承有哪些作用?常用?
? ? - 繼承的概念? :在OOP程序設(shè)計中,當(dāng)我們定義一個class的時候,可以從某個現(xiàn)有的class繼承,新的class稱為子類(Subclass),而被繼承的class稱為基類、父類或超類(Base class、Super class)。
//INPUT:
class Animals(): def say(self): print ( " say something " ) def eat(self): print ( " eat something " ) class Duck(Animals): def say(self): print ( " gaga " ) class Dog(Animals): def say(self): print ( " wangwang " ) class Miao(Animals): def say(self): print ( " miaomiao " ) for i in [Duck(),Dog(),Miao()]: i.eat()
//OUTPUY:
eat something
eat something
eat something
? ? - 繼承的作用:可以解決代碼重用的問題。
? ? - 比較常用的應(yīng)該就是在python相關(guān)web框架里這種比較比較復(fù)雜的框架,和許多第三方庫的類。天知道這些大牛的框架里面默默有效率的幫我們做了多少事- -。天知道我們直接用他們的方法有多方便。
?
2.python多繼承需要注意哪些?用instance和type來判斷python類繼承的關(guān)系。
a.多繼承需要注意的地方:
- 類繼承的順序和方法在多繼承類中查找的順序
? ? --.子類繼承父類時,在子類進(jìn)行屬性調(diào)用的順序為:先查找自己的屬性字典,若自己的屬性字典中無該屬性,則會依次按照繼承父類的順序來依次查找父類的屬性字典;
? ? --.子類繼承父類,當(dāng)父類和子類均有相同的屬性時,子類并不會影響父類的屬性。
總結(jié)起來就是: 按繼承的順序來依次查詢屬性,一旦查到則停止;子類和父類的屬性相互獨立,互不影響;子類可以調(diào)用父類的屬性,反之不行 ;
b.用instance和type來判斷兩個類的關(guān)系
instance和type都是用來判斷參數(shù)1是否是參數(shù)2類型,區(qū)別在于是否會考慮繼承關(guān)系。
# Python3.x 實例: class A: def add(self, x): y = x+1 print (y) class B(A): def add(self, x): super().add(x) b = B() b.add( 2) # 3
# Python2.x 實例: # !/usr/bin/python # -*- coding: UTF-8 -*- class A(object): # Python2.x 記得繼承 object def add(self, x): y = x+1 print (y) class B(A): def add(self, x): super(B, self).add(x) b = B() b.add( 2) # 3
?
C3線性是用于獲取多重繼承下繼承順序的一種算法。通常,被稱為 方法解析順序 ,即MRO(method resolution order)。
算法的名字“C3”并不是縮寫,而是指該算法的三大重要屬性:
- 前趨圖。作為有向無環(huán)圖,找不到任何的循環(huán),通常用前趨圖來理解程序的依賴關(guān)系。
- 保持局部的優(yōu)先次序。
- 單調(diào)性。
C3是1996年首次被提出。在python2.3及后續(xù)版本中,C3被選定為默認(rèn)的解析算法。
一個類的C3線性表,是由兩部分進(jìn)行merge操作得到的,第一部分是是它所有父類的C3線性表(parents' linearizations),第二部分是它所有父類組成的列表(parents list)。后者其實是局部的優(yōu)先級列表。
在C3被應(yīng)用之前,廣度優(yōu)先和深度優(yōu)先是被應(yīng)用于解析順序的。
C3算法計算方法:有點類似拓?fù)渑判颍ㄓ邢驁D) ? ? ?想深刻了解 C3 還是自己查吧...下面有段簡單的多繼承代碼和其對應(yīng)的拓?fù)渑判虻某橄髨D ( 所用代碼實例和圖片均來應(yīng)用自別處,文章末尾有鏈接 )
class D(object): pass class E(object): pass class F(object): pass class C(D, F): pass class B(E, D): pass class A(B, C): pass if __name__ == ' __main__ ' : print A. __mro__
得到的輸出結(jié)果:
(< class ' __main__.A ' >, < class ' __main__.B ' >, < class ' __main__.E ' >, < class ' __main__.C ' >, < class ' __main__.D ' >, < class ' __main__.F ' >,' object ' >)
-
下面就是抽象出來的圖
我們就用拓?fù)渑判騺矸治觯沁@里會碰到同時存在好幾個點都是入度為0 (說人話,就是沒有被別人指向的點),這時按照樹的排序來,即 從左到右,從根到葉 ,這里 A 就是根。
所以具體情況就是:我們先找到了點 A只有它沒有被別人指向,輸出
A
;去掉A及其伸出的兩條線,剩 B 和 C 點同時滿足只指向別人,按照樹的順序從左到右,故先輸出
B
;去掉線剩 E 和 C ,輸出
E
;去線剩 C,輸出
C
;去線剩 D 和 F ,輸出
D
;去線只剩F ,輸出
F
;最后輸出
object
;得到的輸出結(jié)果:?
A B E C D F object
對比系統(tǒng)打印出的結(jié)果,順序是一致的。這樣下次你就可以裝逼地手動計算多繼承時調(diào)用類的順序了
以上結(jié)論來源鏈接:https://www.jianshu.com/p/6651ed35104c
class Bird: def __init__ (self): self.hungry = True def eat(self): if self.hungry: print ' Ahahahah ' else : print ' No thanks! ' class SongBird(Bird): def __init__ (self): self.sound = ' Squawk ' def sing(self): print self.song() sb = SongBird() sb.sing() # 能正常輸出 sb.eat() # 報錯,因為 songgird 中沒有 hungry 特性
這時候,如果需要繼承父類構(gòu)造函數(shù)里的屬性,其實是可以有兩種方法的。
第一種 - 調(diào)用未綁定的超類構(gòu)造方法(多用于舊版 python 陣營)
class SongBird(Bird): def __init__ (self): Bird. __init__ (self) self.sound = ' Squawk ' def sing(self): print self.song()
原理 :在調(diào)用了一個實例的方法時,該方法的self參數(shù)會自動綁定到實例上(稱為綁定方法);如果直接調(diào)用類的方法(比如Bird.__init__),那么就沒有實例會被綁定,可以自由提供需要的self參數(shù)(未綁定方法)。
第二種 - 使用super函數(shù)(只在新式類中有用)
class SongBird(Bird): def __init__ (self): super(SongBird,self). __init__ () self.sound = ' Squawk ' def sing(self): print self.song()
原理: 它會查找所有的超類,以及超類的超類,直到找到所需的特性為止。
from abc import ABC, abstractmethod class Talker(ABC): @abstractmethod def talk(self): pass
結(jié)果:
##抽象基類不能被實例化
>>> Talker() Traceback (most recent call last): File "" , line 1, in TypeError: Can ' t instantiate abstract class Talker with abstract methods talk
##沒有重寫方法的時候,繼承抽象基類的類 本質(zhì)也是抽象類
class Knigget(Talker): pass ##由于沒有重寫方法talk,因此這個類也是抽象的,不能實例化。如果你試圖這樣做,將出現(xiàn)類似于前面的錯誤消息。
###繼承后重寫了方法就沒什么問題
class Knigget(Talker): def talk(self): print ( " Ni! " )
##output:
?
在設(shè)計類的繼承關(guān)系時,通常,主線都是單一繼承下來的,例如,
Ostrich
繼承自
Bird
。但是,如果需要“混入”額外的功能,通過多重繼承就可以實現(xiàn),比如,讓
Ostrich
除了繼承自
Bird
外,再同時繼承
Runnable
。這種設(shè)計通常稱之為Mixin。
為了更好地看出繼承關(guān)系,我們把
Runnable
和
Flyable
改為
RunnableMixin
和
FlyableMixin
。類似的,你還可以定義出肉食動物
CarnivorousMixin
和植食動物
HerbivoresMixin
,讓某個動物同時擁有好幾個Mixin:
class
Dog
(Mammal, RunnableMixin, CarnivorousMixin):
pass
Mixin的目的就是給一個類增加多個功能,這樣,在設(shè)計類的時候,我們優(yōu)先考慮通過多重繼承來組合多個Mixin的功能,而不是設(shè)計多層次的復(fù)雜的繼承關(guān)系。
Python自帶的很多庫也使用了Mixin。舉個例子,Python自帶了
TCPServer
和
UDPServer
這兩類網(wǎng)絡(luò)服務(wù),而要同時服務(wù)多個用戶就必須使用多進(jìn)程或多線程模型,這兩種模型由
ForkingMixin
和
ThreadingMixin
提供。通過組合,我們就可以創(chuàng)造出合適的服務(wù)來。
比如,編寫一個多進(jìn)程模式的TCP服務(wù),定義如下:
class
MyTCPServer
(TCPServer, ForkingMixin):
pass
編寫一個多線程模式的UDP服務(wù),定義如下:
class
MyUDPServer
(UDPServer, ThreadingMixin):
pass
如果你打算搞一個更先進(jìn)的協(xié)程模型,可以編寫一個
CoroutineMixin
:
class
MyTCPServer
(TCPServer, CoroutineMixin):
pass
這樣一來,我們不需要復(fù)雜而龐大的繼承鏈,只要選擇組合不同的類的功能,就可以快速構(gòu)造出所需的子類。
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
