簡體   English   中英

如何從兩個父類調用“重寫”方法?

[英]How to call “overriden” methods from both parent classes?

考慮以下類,其中P1P2C的父類:

class P1:
    def f(self):
        print('P1')


class P2:
    def f(self):
        print('P2')


class C(P1, P2):
    def f(self):
        print('C')
        # super().f()
        # super(P1, self).f()

c = C()
c.f()

當我運行它時,它會打印C

如果我取消注釋第一行super().f() ,那么它也會打印P1
因為super()將從直接父P1調用該方法

如果我取消注釋第二行super(P1, self).f() ,那么它也會打印P2因為super(P1, self)將從P1的兄弟P2調用該方法

我想知道的是,是否有任何方法可以通過一次調用super() function 從父類P1P2調用f方法,而不是像我一樣調用它兩次。

或者,有沒有其他方法可以在不使用super function 的情況下做到這一點?

沒有什么好方法可以完全按照您的意願行事。 但是,如果您可以同時修改P1P2 ,則可以實現協作多個 inheritance,您只需將基礎 class 添加到具有該方法的無操作實現的兩個父類:

class GP: # grandparent base class
    def f(self):
        pass  # do nothing

class P1(GP):
    def f(self):
        print("P1")
        super().f()

class P2(GP):
    def f(self):
        print("P2")
        super().f()

class C(P1, P2):
    def f(self):
        print("C")
        super().f()

這是有效的,因為super並不完全意味着“我的父類”。 這意味着“此對象的 MRO 中的下一個”。 MRO 是 Method Resolution Order,基本上是在 inheritance 中搜索的順序。 當在C中調用super()時,它會在P1中找到方法。 但是當在P1中調用super()時(在C的實例上),它會調用P2 ,因為C實例的 MRO 是[C, P1, P2, GP, object] P2P1之后,所以它被第二個super調用選中。

需要GP class 來結束super調用鏈。 如果你沒有它,最后一個super調用將解析為object (這是所有 inheritance 樹的根),由於沒有這樣的方法,你會得到一個錯誤。 基本 class 中的實現不需要什么都不做,它只需要最后不調用super

Super 從派生的 class 的方法解析順序(MRO)調用下一個方法。

f 方法的每一個實現都應該調用 super,父類之間不需要相互了解,super 會自動調用 MRO 中的 next 方法。

編輯:我忘記了 mro 中的最后一個 class 始終是 object。 object 沒有名為 f 的方法。 因此,您應該注意 mro 中具有該方法的最后一個 class 要么不調用 super().f,要么捕獲 AttributeError。

只要遵循 C3 線性化規則,子 class 就可以更改 MRO。 這意味着派生的 class 決定了哪些代碼可以運行,哪些代碼不能運行。 這是依賴注入的一種方式。

您可以通過 __mro__ 屬性檢查 class 的 MRO。

這個答案主要基於 Raymond Hettinger認為 super的談話

class P1:
    def f(self):
        super().f()
        print('P1')

class P2:
    def f(self):
        print('P2')

class C(P1, P2):
    def f(self):
        super().f()
        print('C')

class C2(P2, P1):
    def f(self):
        super().f()
        print('C2')

>>> C().f()
P2
P1
C
>>> C2().f()
P2
C2
>>> C.__mro__
(<class '__main__.C'>, <class '__main__.P1'>, <class '__main__.P2'>, <type 'object'>)
>>> C2.__mro__
(<class '__main__.C2'>, <class '__main__.P2'>, <class '__main__.P1'>, <type 'object'>)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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