繼承,只的是單繼承(1對1)。但多重繼承比較接近多型,因為它會分為多調一或一調多。這樣就會牽扯到MRO(方法順序),但不管哪一個;都會繼承主類別(class)的特性。
#一調多
class A:
print('A')
class B:
print('B')
class C:
print('C')
class D(A, B, C):
pass
D()
#多調一
class A:
print('all_ABCD')
class B(A):
pass
class C(A):
pass
class D(A):
pass
B() , C() , D()
之前有提到super()函式,它的主要目的不是為了簡化。而是處理多承的問題
像__init__它是class第一個呼叫的名稱,但一個class只能呼叫一個__init__,這時運用super()就可解決(破除名稱唯一性)。
class A:
def __init__(self):
self.a = "A"
def fc_a(self):
print(self.a)
class B:
def __init__(self):
self.b = "B"
def fc_b(self):
print(self.b)
class C:
def __init__(self):
self.c = "C"
def fc_c(self):
print(self.c)
class D(A, B, C):
def __init__(self):
super().__init__()
super(A, self).__init__()
super(B, self).__init__()
super(C, self).__init__() #super調用每個class內指定__init__
d = D()
d.fc_a()
d.fc_b()
d.fc_c()
每個繼承都有__init__,到底要看哪個子繼承呢?透過super()的安排就能把第一個回傳class轉為子繼承的class。
class bank(object):
#每次執行都返回__init__ 把acct跟pwd 初始化為0
def __init__(self, acct=None , pwd=None):
self.acct = acct
self.pwd = pwd
def sss(self):
print(f'welcome~{self.acct}')
print(f'pwd is {self.pwd}')
class DB(bank):
def code(self):
super().sss()
d = DB()
print('初始化為:')
d.code()
這樣繼承時也可延續主要class的『模板』,也是一種使程式更簡潔的用法。
這種用法常配合陣列把資料存進去,類似資料庫的方法
假如有個多重繼承同時要讓所有子class輸出,會發現輸出跟原程式輸出順序不同。
沒錯,因為每個輸出都會因繼承方法而影響屬性(權限高低)而有不同的輸出。此為MRO(方法解析順序)查詢方法:使用__mro__來讀取繼承順序
class A():
print('all_ABCD')
def A_fc(self):
print('A_fc')
class B(C):
print('B_class')
class C(A):
print('C_class')
class D(B , A):
pass
print(A.__mro__,'\n',B.__mro__,'\n',C.__mro__,'\n',D.__mro__)
=> 代表繼承
A => init
B => C => A => init
C => A => init
D => B => C => A => A(遞迴) => init
python2.3之後就改進了以往其他程式語言的邏輯 讓程式有了人類的繼承邏輯。如有繼承的衝突,它會報錯。此稱為c3線性化
class A():
print('all_ABCD')
def __init__(self):
print('__init__')
class B(A , C , B):
print('B_class')
class C(A ,D , C):
print('C_class')
class D(B ,A,D):
pass
print(B.__mro__,'\n',C.__mro__,'\n',A.__mro__,'\n',D.__mro__)
Out[ ]:TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, B, C