Day31:繼承實現的原理
一、繼承實現的原來
1、繼承順序
Python的類可以繼承多個類。繼承多個類的時候,其屬性的尋找的方法有兩種,分別是深度優先和廣度優先。
如下的結構,新式類和經典類的屬性查找順序都一致。順序為D--->A--->E--->B--->C。
class E: def test(self): print(‘from E‘) class A(E): def test(self): print(‘from A‘) class B: def test(self): print(‘from B‘) classC: def test(self): print(‘from C‘) class D(A,B,C): def test(self): print(‘from D‘) d=D() d.test() print(D.mro()) #新式類才可以查看.mro()方法查看查找順序 ‘‘‘ from D [<class ‘__main__.D‘>, <class ‘__main__.A‘>, <class ‘__main__.E‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘object‘>]‘‘‘
如下的結構,新式類和經典類的屬性查找順序就不一樣了。
經典類遵循深度優先,其順序為:F--->E--->B--->A--->F--->C--->G--->D
新式類遵循廣度優先,其順序為:F--->E--->B--->F--->C--->G--->D--->A
2、繼承原理
python到底是如何實現繼承的,對於你定義的每一個類,python會計算出一個方法解析順序(MRO)列表,這個MRO列表就是一個簡單的所有基類的線性順序列表,例如:
print(D.mro()) ‘‘‘ [<class ‘__main__.D‘>, <class ‘__main__.A‘>, <class ‘__main__.E‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘object‘>]‘‘‘
為了實現繼承,python會在MRO列表上從左到右開始查找基類,直到找到第一個匹配這個屬性的類為止。
而這個MRO列表的構造是通過一個C3線性化算法來實現的。我們不去深究這個算法的數學原理,它實際上就是合並所有父類的MRO列表並遵循如下三條準則:
1.子類會先於父類被檢查。
2.多個父類會根據它們在列表中的順序被檢查。
3.如果對下一個類存在兩個合法的選擇,選擇第一個父類。
二、子類中調用父類的方法
子類繼承了父類的方法,然後想進行修改,註意了是基於原有的基礎上修改,那麽就需要在子類中調用父類的方法。
方法一:父類名.父類方法()
#_*_coding:utf-8_*_ class Vehicle: #定義交通工具類 Country=‘China‘ def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print(‘開動啦...‘) class Subway(Vehicle): #地鐵 def __init__(self,name,speed,load,power,line): Vehicle.__init__(self,name,speed,load,power) self.line=line def run(self): print(‘地鐵%s號線歡迎您‘ %self.line) Vehicle.run(self) line13=Subway(‘中國地鐵‘,‘180m/s‘,‘1000人/箱‘,‘電‘,13) line13.run()View Code
方法二:super()
class Vehicle: #定義交通工具類 Country=‘China‘ def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print(‘開動啦...‘) class Subway(Vehicle): #地鐵 def __init__(self,name,speed,load,power,line): #super(Subway,self) 就相當於實例本身 在python3中super()等同於super(Subway,self) super().__init__(name,speed,load,power) self.line=line def run(self): print(‘地鐵%s號線歡迎您‘ %self.line) super(Subway,self).run() class Mobike(Vehicle):#摩拜單車 pass line13=Subway(‘中國地鐵‘,‘180m/s‘,‘1000人/箱‘,‘電‘,13) line13.run()View Code
不用super引發的慘案
#每個類中都繼承了且重寫了父類的方法 class A: def __init__(self): print(‘A的構造方法‘) class B(A): def __init__(self): print(‘B的構造方法‘) A.__init__(self) class C(A): def __init__(self): print(‘C的構造方法‘) A.__init__(self) class D(B,C): def __init__(self): print(‘D的構造方法‘) B.__init__(self) C.__init__(self) f1=D() print(D.__mro__) ‘‘‘ D的構造方法 B的構造方法 A的構造方法 C的構造方法 A的構造方法 (<class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>) ‘‘‘
使用super()的結果
class A: def __init__(self): print(‘A的構造方法‘) class B(A): def __init__(self): print(‘B的構造方法‘) super().__init__() #super(B,self).__init__() class C(A): def __init__(self): print(‘C的構造方法‘) super().__init__() #super(C,self).__init__() class D(B,C): def __init__(self): print(‘D的構造方法‘) super().__init__() #super(D,self).__init__() # C.__init__(self) f1=D() print(D.__mro__) ‘‘‘ D的構造方法 B的構造方法 C的構造方法 A的構造方法 (<class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>) ‘‘‘
當你使用super()函數時,Python會在MRO列表上繼續搜索下一個類。只要每個重定義的方法統一使用super()並只調用它一次,那麽控制流最終會遍歷完整個MRO列表,每個方法也只會被調用一次(註意註意註意:使用super調用的所有屬性,都是從MRO列表當前的位置往後找,千萬不要通過看代碼去找繼承關系,一定要看MRO列表)
三、
Day31:繼承實現的原理