如何从父 类 调用 "overriden" 方法?
How to call "overriden" methods from both parent classes?
考虑以下 类,其中 P1
和 P2
是 C
的父级 类:
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
的方法
我想知道的是,如果有任何方法可以通过一次调用从父 类 P1
和 P2
调用 f
方法super()
函数,而不是像我那样调用它两次。
或者,有没有其他方法可以在不使用 super
函数的情况下做到这一点?
没有什么好的方法可以完全按照您的意愿行事。但是如果可以同时修改P1
和P2
,就可以实现协同多重继承,只需要在父class的两个父class中添加一个baseclass即可该方法的无操作实现:
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
并不完全意味着 "my parent class"。意思是"next in the MRO' for this object"。 MRO 是方法解析顺序,基本上是在继承中搜索事物的顺序。当在C
中调用super()
时,它会找到P1
中的方法。但是当在 P1
中调用 super()
时(在 C
的实例上),它调用 P2
,因为 C
实例的 MRO 是 [C, P1, P2, GP, object]
. P2
出现在 P1
之后,因此它被第二个 super
调用选中。
需要 GP
class 来结束 super
调用链。如果您没有它,最后的 super
调用将解析为 object
(这是所有继承树的根)并且由于没有这样的方法,您会得到一个错误。基础class中的实现不需要什么都不做,只需要最后不调用super
即可。
Super从派生的方法解析顺序(MRO)调用下一个方法class.
方法f的每一个实现都应该调用super,parent classes之间不需要相互了解,super会自动调用MRO中的next方法
编辑:我忘记了 mro 中的最后一个 class 总是 object。
object 没有名为 f 的方法。所以你应该注意 mro 中最后一个 class 有那个方法,要么不调用 super().f 要么捕获 AttributeError.
只要遵循C3线性化规则,childclass就可以改MRO。这意味着派生的 class 决定了哪些代码获得 运行 以及哪些代码没有获得 运行。这是依赖注入的一种方式。
您可以通过 __mro__ 属性检查 class 的 MRO。
此答案主要基于 Raymond Hettinger
的演讲 super considered 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'>)
考虑以下 类,其中 P1
和 P2
是 C
的父级 类:
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
我想知道的是,如果有任何方法可以通过一次调用从父 类 P1
和 P2
调用 f
方法super()
函数,而不是像我那样调用它两次。
或者,有没有其他方法可以在不使用 super
函数的情况下做到这一点?
没有什么好的方法可以完全按照您的意愿行事。但是如果可以同时修改P1
和P2
,就可以实现协同多重继承,只需要在父class的两个父class中添加一个baseclass即可该方法的无操作实现:
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
并不完全意味着 "my parent class"。意思是"next in the MRO' for this object"。 MRO 是方法解析顺序,基本上是在继承中搜索事物的顺序。当在C
中调用super()
时,它会找到P1
中的方法。但是当在 P1
中调用 super()
时(在 C
的实例上),它调用 P2
,因为 C
实例的 MRO 是 [C, P1, P2, GP, object]
. P2
出现在 P1
之后,因此它被第二个 super
调用选中。
需要 GP
class 来结束 super
调用链。如果您没有它,最后的 super
调用将解析为 object
(这是所有继承树的根)并且由于没有这样的方法,您会得到一个错误。基础class中的实现不需要什么都不做,只需要最后不调用super
即可。
Super从派生的方法解析顺序(MRO)调用下一个方法class.
方法f的每一个实现都应该调用super,parent classes之间不需要相互了解,super会自动调用MRO中的next方法
编辑:我忘记了 mro 中的最后一个 class 总是 object。 object 没有名为 f 的方法。所以你应该注意 mro 中最后一个 class 有那个方法,要么不调用 super().f 要么捕获 AttributeError.
只要遵循C3线性化规则,childclass就可以改MRO。这意味着派生的 class 决定了哪些代码获得 运行 以及哪些代码没有获得 运行。这是依赖注入的一种方式。
您可以通过 __mro__ 属性检查 class 的 MRO。
此答案主要基于 Raymond Hettinger
的演讲 super considered superclass 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'>)