这是我试图编写的代码:
class A(object):
def bind_foo(self):
old_foo = self.foo
def new_foo():
old_foo()
#super().foo()
super(self.__class__,self).foo()
self.foo = new_foo
def __init__(self):
print("A __init__")
def foo(self):
print("A foo")
class B(A):
def __init__(self):
print("B __init__")
super().__init__()
def foo(self):
print("B foo")
super().foo()
class C(A):
def __init__(self):
print("C __init__")
super().__init__()
super().bind_foo()
def foo(self):
print("C foo")
b = B()
b.foo()
c = C()
c.foo()
B类和A类是预期的行为,也就是说,当我致电b.foo()
时,它会调用a.foo()
以及super()
。 C类试图模仿子B和父A行为,但这次我不想明确地将super().foo()
放在子类中,但我仍然希望调用父foo()
。它按预期工作。
然而,我不明白的是,在A.bind_foo
下,我必须使用super(self.__class__,self).foo()
而不是super().foo
。 super().foo
给出了
"SystemError: super(): no arguments".
有人可以解释为什么会这样吗?
答案 0 :(得分:17)
在致电self.__class__
时,
在Python 3中,对不带参数的type(self)
的调用等同于super()
(在类super()
上的方法中);请注意类的显式命名。 Python编译器将super(B, self)
闭包单元添加到使用B
而不带参数的方法(请参阅Why is Python 3.x's super() magic?),该参数引用正在定义的当前类。
如果使用__class__
或super()
,当子类尝试调用该方法时,您将遇到无限递归异常;那时super(self.__class__, self)
派生类,而不是原始类。见When calling super() in a derived class, can I pass in self.__class__?
总而言之,在Python 3中:
super(type(self), self)
等于:
self.__class__
但你应该使用前者,因为它可以让你自己重复。
在Python 2中,您只能使用第二种形式 。
对于你的class B(A):
def __init__(self):
print("B __init__")
super().__init__()
def foo(self):
print("B foo")
super().foo()
方法,你必须传入一个显式类来从中搜索MRO,因为Python编译器在这里无法确定绑定新替换时使用的是哪个类{{1 }}:
class B(A):
def __init__(self):
print("B __init__")
super(B, self).__init__()
def foo(self):
print("B foo")
super(B, self).foo()
你可以使用bind_foo()
(没有foo
)让Python为你提供闭包单元格,但这是对def bind_foo(self, klass=None):
old_foo = self.foo
if klass is None:
klass = type(self)
def new_foo():
old_foo()
super(klass, self).foo()
self.foo = new_foo
的引用,这里没有__class__
。当您绑定新的self
时,您希望在MRO中搜索重写的方法,而不是开始在A
进行搜索。
请注意,如果您现在创建一个类C
,从foo
进行子类化,则会再次出现错误,因为现在您正在调用C
并在以D
而不是C
作为起点,转而致电bind_foo()
。您最好的选择是使用显式类引用来调用super()
。这里D
(没有C
)会做得很好:
bind_foo()
现在,您具有与不带参数的__class__
相同的行为,对当前类的引用(您在其中定义方法self.
的引用)将被传递到class C(A):
def __init__(self):
print("C __init__")
super().__init__()
self.bind_foo(__class__)
,使super()
的行为就像直接在__init__
的类定义中定义一样。
请注意,在此处super()
调用new_foo()
是没有意义的;您没有在此处覆盖它,因此您只需拨打C
即可。