pythonsuper_用__init __()方法理解Python super()
我想了解一下 super()
我們使用的原因super是,可能使用協作多重繼承的子類將在方法解析順序(MRO)中調用正確的下一個父類函數。
在Python 3中,我們可以像這樣調用它:class ChildB(Base):
def __init__(self):
super().__init__()
在Python 2中,我們需要像這樣使用它:super(ChildB, self).__init__()
沒有超級,您使用多重繼承的能力有限:Base.__init__(self) # Avoid this.
我在下面進一步解釋。“這段代碼實際上有什么區別?:”class ChildA(Base):
def __init__(self):
Base.__init__(self)class ChildB(Base):
def __init__(self):
super(ChildB, self).__init__()
# super().__init__() # you can call super like this in Python 3!
這段代碼的主要區別在于你在__init__with中獲得了一個間接層super,它使用當前類來確定__init__要在MRO中查找的下一個類。
我在規范問題的答案中說明了這種差異,如何在Python中使用'super'?,它演示了依賴注入和協作多重繼承。
如果Python沒有 super
這里的代碼實際上非常等同于super(如何在C中實現,減去一些檢查和回退行為,并轉換為Python):class ChildB(Base):
def __init__(self):
mro = type(self).mro() # Get the Method Resolution Order.
check_next = mro.index(ChildB) + 1 # Start looking after *this* class.
while check_next < len(mro):
next_class = mro[check_next]
if '__init__' in next_class.__dict__:
next_class.__init__(self)
break
check_next += 1
寫得更像本機Python:class ChildB(Base):
def __init__(self):
mro = type(self).mro()
for next_class in mro[mro.index(ChildB) + 1:]: # slice to end
if hasattr(next_class, '__init__'):
next_class.__init__(self)
break
如果我們沒有該super對象,我們必須在任何地方編寫此手動代碼(或重新創建它!)以確保我們在方法解析順序中調用正確的下一個方法!
超級如何在沒有明確告知調用方法的哪個類和實例的情況下在Python 3中執行此操作?
它獲取調用堆棧幀,并找到類(隱式存儲為本地自由變量,__class__使調用函數成為類的閉包)和該函數的第一個參數,該參數應該是通知它的實例或類要使用的方法解決順序(MRO)。
因為它需要MRO的第一個參數,所以使用super靜態方法是不可能的。
對其他答案的批評:使用super()可以避免顯式引用基類,這可能很好。。但主要優勢在于多重繼承,可以發生各種有趣的事情。如果您還沒有,請參閱super上的標準文檔。
這是相當浪漫的,并沒有告訴我們太多,但重點super是不要避免編寫父類。重點是確保調用方法解析順序(MRO)中的下一個方法。這在多重繼承中變得很重要。
我會在這里解釋一下。class Base(object):
def __init__(self):
print("Base init'ed")class ChildA(Base):
def __init__(self):
print("ChildA init'ed")
Base.__init__(self)class ChildB(Base):
def __init__(self):
print("ChildB init'ed")
super(ChildB, self).__init__()
讓我們創建一個我們希望在Child之后調用的依賴項:class UserDependency(Base):
def __init__(self):
print("UserDependency init'ed")
super(UserDependency, self).__init__()
現在記住,ChildB使用超級,ChildA不是:class UserA(ChildA, UserDependency):
def __init__(self):
print("UserA init'ed")
super(UserA, self).__init__()class UserB(ChildB, UserDependency):
def __init__(self):
print("UserB init'ed")
super(UserB, self).__init__()
并且UserA不調用UserDependency方法:>>> UserA()UserA init'ed
ChildA init'edBase init'ed
<__main__.UserA object at 0x0000000003403BA8>
但是UserB,因為ChildB使用super,確實!:>>> UserB()UserB init'ed
ChildB init'edUserDependency init'ed
Base init'ed<__main__.UserB object at 0x0000000003403438>
對另一個答案的批評
在任何情況下都不應該執行以下操作,這是另一個答案所暗示的,因為當您繼承ChildB時肯定會出錯:super(self.__class__, self).__init__() # Don't do this. Ever.
(這個答案并不聰明或特別有趣,但盡管評論中有直接的批評和超過17個downvotes,但回答者堅持提出建議,直到一位善良的編輯解決了他的問題。)
說明:那個回答建議像這樣調用super:super(self.__class__, self).__init__()
這是完全錯誤的。super讓我們在子類中查找MRO中的下一個父級(請參閱本答案的第一部分)。如果你告訴super我們在子實例的方法中,那么它將在行中查找下一個方法(可能是這個)導致遞歸,可能導致邏輯失敗(在回答者的例子中,它確實)或者RuntimeError當遞歸深度時超過了。>>> class Polygon(object):... def __init__(self, id):... self.id = id...>>> class Rectangle(Polygon):...
def __init__(self, id, width, height):... super(self.__class__, self).__init__(id)...
self.shape = (width, height)...>>> class Square(Rectangle):... pass...>>> Square('a', 10, 10)Traceback (most recent call last):
File "", line 1, in
File "", line 3, in __init__TypeError: __init__() missing 2 required positional arguments: 'width' and 'height'
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的pythonsuper_用__init __()方法理解Python super()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: beanpostprocessor使用场
- 下一篇: 滴滴战略投资时空电动 更好的推广电动汽车