super()內置函數
父類的構造函數必須手動調用, 調用方式有2種:
1. MyParentClass.__init__(xxx)
2. super(MyClass, self).__init__(xxx)
區別在於: 1比較直觀, 在涉及多重繼承時, 可以手動控制父類構造函數的調用順序, 需要手動爲每個父類調用一次構造函數; 2比較靈活, 動態查找父類, 在涉及多重繼承時, 會自動調用各個直接父類的構造函數;
class A(object):
def __init__(self):
super(A, self).__init__()
print '__init__ A'
class B(A):
def __init__(self):
super(B, self).__init__()
print '__init__ B'
class C(B):
def __init__(self):
super(C, self).__init__()
print '__init__ C'
class AA(object):
def __init__(self):
super(AA, self).__init__()
print '__init__ AA'
class D(A, AA):
def __init__(self):
super(D, self).__init__()
print '__init__ D'
d = D()
# 自動調用所以直接父類的構造函數
#__init__ AA
#__init__ A
#__init__ D
class BB(A):
def __init__(self):
print '__init__ BB'
class CC(BB):
def __init__(self):
super(CC, self).__init__()
print '__init__ CC'
cc = CC()
# super()只會查找直接父類, 不會遞歸查找, 所以, 因爲BB沒有調動super, 所以A的構造函數就被調用
#__init__ BB
#__init__ CC
c = C()
# 當前類和父類都調用了super, 所以才能保證繼承鏈上的所有構造函數都被調用
#__init__ A
#__init__ B
#__init__ C
三角繼承
# 直接報錯
class A:
pass
class B(A):
pass
class C(B, A):
pass
c = C()
#TypeError: Error when calling the metaclass bases
#Cannot create a consistent method resolution
#order (MRO) for bases B, A
報錯原因
C繼承A和B, 同時B也繼承A, 對C來說, B和A是它的2個直接父類, 所以C在進行方法查找時, A和B具有相同的優先級, 但是這時候問題就來了:
1. 如果先從A再B, 那麼B會覆蓋A的方法(當然了, 這是我們所期望的, 因爲B是A子類, 子類覆蓋父類, 是理所當然的)
2. 如果先從B再A, 那麼A會覆蓋B的方法(出錯了吧! 父類方法怎麼可以覆蓋子類方法呢!)
以上2種情況均可能出現, 這導致了方法解析順序(MRO)不一致
解決方法
既然B繼承A, 那麼B已經包含了A的全部內容, 所以直接繼承B就可以了, 沒有必要繼承A了:
class C(B):
pass
萬事大吉!
菱形繼承
class A(object):
def __init__(self):
super(A, self).__init__()
print '__init__ A'
class B(A):
def __init__(self):
super(B, self).__init__()
print '__init__ B'
class C(A):
def __init__(self):
super(C, self).__init__()
print '__init__ C'
class D(B, C):
def __init__(self):
super(D, self).__init__()
print '__init__ D'