[英]Calling super.__init__() in a subclass of tornado TCPServer
[英]Understanding difference between parent class init() and super.__init__
我查看了答案https://stackoverflow.com/a/33469090/11638153和https://stackoverflow.com/a/27134600但不明白什么是“間接”。 具體來說,如果我有像下面這樣的類,那么硬編碼父 class __init__()
是否有任何缺點或優點,就像在 class Child1
中所做的那樣(當我們可以顯式編寫__init__()
方法來調用時,為什么我們需要super()
)?
class Base1:
def __init__(self):
print("Class Base1 init()")
class Base2:
def __init__(self):
print("Class Base2 init()")
class Child1(Base1, Base2):
def __init__(self):
print("Class Child1 init()")
Base1.__init__(self)
Base2.__init__(self)
class Child2(Base1, Base2):
def __init__(self):
print("Class Child2 init()")
super().__init__()
if __name__ == "__main__":
obj1 = Child1()
print("---")
obj2 = Child2()
粗略地說,區別在於ParentClass.__init__(self)
總是調用特別命名的 class 而super().__init__()
進行運行時計算以確定要調用哪個 class。
在許多情況下,這兩種方法給出了相同的結果。 然而, super()
更強大。 它是一個多 inheritance 方案,它可能會調用一些 class,而不是當前 class 的父級。 本文詳細介紹了后一種情況。
對於單個 inheritance,更喜歡super()
的原因是它讀取良好,並且通過計算父 class 使維護更容易。
對於多個 inheritance, super()
是按照調用實例的 class 的MRO順序訪問父類的唯一直接方法。 如果這些話對您沒有任何意義,請查看參考文章。
在您的示例代碼中, Child1
的設計非常脆弱。 如果它的兩個基類共享一些共同的基類(並在輪到它們自己的時候調用它們自己的父類的__init__
方法),那么祖父類 class 可能會被初始化多次,如果計算成本高或有副作用,那就不好了。 這是 inheritance 層次結構的“菱形模式”,在許多允許多個 inheritance 的語言(如 C++)中可能會很麻煩。
這是一個可以通過顯式父調用產生的壞問題的示例,而super()
旨在解決該問題:
class Grandparent:
def __init__(self):
print("Grandparent")
class Parent1(Grandparent):
def __init__(self):
print("Parent1")
Grandparent.__init__(self)
class Parent2(Grandparent):
def __init__(self):
print("Parent2")
Grandparent.__init__(self)
class Child(Parent1, Parent2):
def __init__(self):
print("Child")
Parent1.__init__(self)
Parent2.__init__(self)
c = Child() # this causes "Grandparent" to be printed twice!
Python 的解決方案是使用super()
,它允許協作多個 inheritance。 每個 class 必須設置才能使用它,包括中間基類! 一旦您將所有內容設置為使用super
,它們就會在必要時互相調用,並且不會被調用不止一次。
class Grandparent:
def __init__(self):
print("Grandparent")
class Parent1(Grandparent):
def __init__(self):
print("Parent1")
super().__init__()
class Parent2(Grandparent):
def __init__(self):
print("Parent2")
super().__init__()
class Child(Parent1, Parent2):
def __init__(self):
print("Child")
super().__init__()
c = Child() # no extra "Grandparent" printout this time
事實上,Python 中的每個多重繼承實例都是菱形的,其Grandparent
class 為object
(如果不是其他的話)。 object
class 有一個__init__
方法,它不需要 arguments (除了self
)並且什么都不做。
需要注意的是,來自ParentX
類的super().__init__
調用並不總是 go 直接到Grandparent
。 在初始化Parent1
或Parent2
的實例時,它們會,但是在實例化Child
的實例時, Parent1.__init__
的調用將 go 到Parent2.__init__
,並且只有從那里Parent2
的super
調用 go 到Grandparent.__init__
.
super
調用解析到的位置取決於調用方法的實例的 MRO(方法解析順序)。 super
調用通常意味着“在 MRO 中的下一個class 中找到此方法”,相對於它的調用位置。 您可以通過調用SomeClass.mro()
查看 class 的 MRO。 對於我的示例中的Child
,它是: [Child, Parent1, Parent2, Grandparent, object]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.