簡體   English   中英

了解父 class init() 和 super.__init__ 之間的區別

[英]Understanding difference between parent class init() and super.__init__

我查看了答案https://stackoverflow.com/a/33469090/11638153https://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 在初始化Parent1Parent2的實例時,它們會,但是在實例化Child的實例時, Parent1.__init__的調用將 go 到Parent2.__init__ ,並且只有從那里Parent2super調用 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM