Python 之 super MRO (没有遇到过适用场景)
WOW!!!
這里wow的是真尼瑪繞且沒看完,
好困吶,貼上網(wǎng)址,等自己英文好一點(diǎn)再看(https://rhettinger.wordpress.com/2011/05/26/super-considered-super/),,,,
自己的理解:
先上例子:
例1:
class A(object):def __init__(self):print "enter A"print "leave A"class B(object):def __init__(self):print "enter B"print "leave B"class C(A):def __init__(self):print "enter C"super(C, self).__init__()print "leave C"class D(A):def __init__(self):print "enter D"super(D, self).__init__()print "leave D"class E(B, C):def __init__(self):print "enter E"B.__init__(self)C.__init__(self)print "leave E"class F(E, D):def __init__(self):print "enter F"E.__init__(self)D.__init__(self)print "leave F"輸出:
enter Fenter Eenter Bleave Benter Center Denter Aleave Aleave Dleave Cleave Eenter Denter Aleave Aleave Dleave F按我們對(duì)super的理解,從圖中可以看出,在調(diào)用類C的初始化函數(shù)時(shí),應(yīng)該是調(diào)用類A的初始化函數(shù),但事實(shí)上卻調(diào)用了類D的初始化函數(shù)。好一個(gè)詭異的問題!并且類A和類D的初始化函數(shù)被重復(fù)調(diào)用了2次
這是為什么呢?
super不是簡(jiǎn)單地調(diào)用所謂基類的方法,而是調(diào)用MRO中的下一個(gè)類的方法,也就是類似于next的方法。
mro中記錄了一個(gè)類的所有基類的類類型序列。查看mro的記錄,發(fā)覺包含7個(gè)元素,7個(gè)類名分別為:F E B C D A object
從而說明了為什么在C.__init__中使用super(C, self).__init__()會(huì)調(diào)用類D的初始化函數(shù)了。
不要一說到 super 就想到父類!super 指的是 MRO 中的下一個(gè)類!
MRO & super
Method resolution order是python用來(lái)解析方法調(diào)用順序的。MRO對(duì)于多重繼承中方法調(diào)用異常重要。python中有一個(gè)內(nèi)建函數(shù)和MRO密切相關(guān)——super。具體實(shí)現(xiàn)方式,有興趣可以以后看看。
在 MRO 中,基類永遠(yuǎn)出現(xiàn)在派生類后面,如果有多個(gè)基類,基類的相對(duì)順序保持不變。
super做了什么?
def super(cls, inst):mro = inst.__class__.mro()return mro[mro.index(cls) + 1]兩個(gè)參數(shù) cls 和 inst 分別做了兩件事:
1. inst 負(fù)責(zé)生成 MRO 的 list
2. 通過 cls 定位當(dāng)前 MRO 中的 index, 并返回 mro[index + 1]
super的作用是什么呢?
按名字繼承的話,如果子類的父類發(fā)生變化時(shí),必須要全部替換名字,比較麻煩;
?
如果沒有復(fù)雜的繼承結(jié)構(gòu),super 作用不大。
例2:(沒太看懂這貨)
class A(object):def __init__(self):print "enter A"super(A, self).__init__() # new 寄幾繼承寄幾是什么鬼?print "leave A"class B(object):def __init__(self):print "enter B"super(B, self).__init__() # newprint "leave B"class C(A):def __init__(self):print "enter C"super(C, self).__init__()print "leave C"class D(A):def __init__(self):print "enter D"super(D, self).__init__()print "leave D"class E(B, C):def __init__(self):print "enter E"super(E, self).__init__() # changeprint "leave E"class F(E, D):def __init__(self):print "enter F"super(F, self).__init__() # changeprint "leave F"輸出:
enter Fenter Eenter Benter Center Denter Aleave Aleave Dleave Cleave Bleave Eleave F明顯地,F的初始化不僅完成了所有的父類的調(diào)用,而且保證了每一個(gè)父類的初始化函數(shù)只調(diào)用一次。
?
那么,總結(jié):
1. super并不是一個(gè)函數(shù),是一個(gè)類名,形如super(B, self)事實(shí)上調(diào)用了super類的初始化函數(shù),?產(chǎn)生了一個(gè)super對(duì)象;
2. super類的初始化函數(shù)并沒有做什么特殊的操作,只是簡(jiǎn)單記錄了類類型和具體實(shí)例;
3. super(B, self).func的調(diào)用并不是用于調(diào)用當(dāng)前類的父類的func函數(shù);
4. Python的多繼承類是通過mro的方式來(lái)保證各個(gè)父類的函數(shù)被逐一調(diào)用,而且保證每個(gè)父類函數(shù)只調(diào)用一次(如果每個(gè)類都使用super);
?
如果類被設(shè)計(jì)成使用了super,那么所有子類也必須要調(diào)用super,否則直接調(diào)用會(huì)出現(xiàn)重復(fù)調(diào)用的問題
?
5. 混用super類和非綁定的函數(shù)是一個(gè)危險(xiǎn)行為,這可能導(dǎo)致應(yīng)該調(diào)用的父類函數(shù)沒有調(diào)用或者一個(gè)父類函數(shù)被調(diào)用多次。(保持一致性。要不全部用類名調(diào)用父類,要不就全部用 super,不要一半一半。)
?
參考:
http://www.cnblogs.com/lovemo1314/archive/2011/05/03/2035005.html(super)
http://blog.csdn.net/rommi/article/details/51058360(MRO)
http://blog.csdn.net/seizef/article/details/5310107(super & MRO)?
??
轉(zhuǎn)載于:https://www.cnblogs.com/pannyvan/p/6135190.html
總結(jié)
以上是生活随笔為你收集整理的Python 之 super MRO (没有遇到过适用场景)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 20145202、20145225、20
- 下一篇: python 读帧和绘图的区别