先看示例代碼:
def foo(self):
print('Top')
class Middle(Top):
def foo(self):
print('Middle')
super(self.__class__, self).foo()
class Bottom(Middle):
pass
b = Bottom()
繼續執行時如下這行代碼時:
報RuntimeError: maximum recursion depth exceeded while calling a Python object。
看來是由於遞歸的關係導致Python棧溢出了(CPython的函數棧很淺,使用遞歸要小心)。通過traceback信息和debug日誌知道,根本原因是Middle.foo被遞歸執行了,爲什麼會出現這樣的錯誤呢?這段代碼很普通嘛,只是最底層的子類想要使用中間父類的方法而已,這種場景太常見了,答案在super的機制上,super(type, object).method()會以實例object調用類型type的父類所定義的方法method。
b.foo()的方法查找順序是:
1、查找實例本身
2、實例的類
3、父類Middle
執行到父類的foo處,此時代碼中的self所指代的實例是Bottom的實例,self.__class__是Bottom,杯具就在這裏了,super(self.__class__, self).foo()會反覆的調用Middle.foo……
要解決這個問題很簡單,老老實實用super沒出現前的寫法即可:
def foo(self):
print('Middle')
Top.foo(self)
如此調用目標就很明確了。