No *_*ing 4 python inheritance class
这是我试图编写的代码:
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()
Run Code Online (Sandbox Code Playgroud)
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".
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么会这样吗?
Mar*_*ers 18
你应该不使用self.__class__或type(self)调用时super().
在Python 3中,对super()不带参数的调用等同于super(B, self)(在类中的方法内B); 注意类的显式命名.Python编译器__class__为不使用super()参数的方法添加一个闭包单元(请参阅为什么Python 3.x的super()魔术?)引用当前类正在定义.
如果使用super(self.__class__, self)or super(type(self), self),当子类尝试调用该方法时,您将遇到无限递归异常; 那个时候self.__class__是派生类,而不是原始类.请参阅在派生类中调用super()时,是否可以传入self .__ class__?
那么,总结一下,在Python 3中:
class B(A):
def __init__(self):
print("B __init__")
super().__init__()
def foo(self):
print("B foo")
super().foo()
Run Code Online (Sandbox Code Playgroud)
等于:
class B(A):
def __init__(self):
print("B __init__")
super(B, self).__init__()
def foo(self):
print("B foo")
super(B, self).foo()
Run Code Online (Sandbox Code Playgroud)
但你应该使用前者,因为它可以节省你重复自己.
在Python 2,你被卡住第二种形式只.
对于您的bind_foo()方法,您必须传入一个显式类来从中搜索MRO,因为Python编译器无法在此确定绑定新替换时使用的类foo:
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
Run Code Online (Sandbox Code Playgroud)
您可以使用__class__(no self)让Python为您提供闭包单元格,但这是一个引用A,而不是C在这里.当您绑定新的时foo,您希望在MRO中搜索重写的方法以开始搜索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__)
Run Code Online (Sandbox Code Playgroud)
现在,您具有与super()不使用参数相同的行为,对当前类的引用(定义方法的类__init__)将被传递给super(),使得new_foo()行为就好像它是直接在类定义中定义的那样C.
请注意,bind_foo()在super()这里呼吁没有意义; 你没有在这里覆盖它,所以你可以调用它self.bind_foo().
| 归档时间: |
|
| 查看次数: |
6588 次 |
| 最近记录: |