我想知道是否有人可以解释并提供此问题的解决方案:
$ cat object-override-methods.py
class A:
def foo(self):
return 1
class B:
def foo(self):
return 1
for klass in A, B:
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
A().foo()
B().foo()
$ python object-override-methods.py
Traceback (most recent call last):
File "object-override-methods.py", line 15, in <module>
A().foo()
File "object-override-methods.py", line 12, in foo
return orig_foo(self) * 2
TypeError: unbound method foo() must be called with B instance as first argument (got A instance instead)
提前致谢。
答案 0 :(得分:2)
因为orig_foo
是在全局范围内定义的,所以每次循环时都会践踏它的值。然后,每个新的foo
方法都会共享这个被践踏的值。
一个简单的解决方法是将代码移动到一个函数中,如下所示:
def rebind_foo(klass):
orig_foo = klass.foo
def foo(self):
return orig_foo(self) * 2
klass.foo = foo
for klass in A, B:
rebind_foo(klass)
这可确保每个新的foo
方法都获得自己的orig_foo
值。
答案 1 :(得分:2)
orig_foo
是一个全局变量,每次循环都会改变值。循环完成后,orig_foo
引用B.foo
。
内部函数foo
(一个或每个遍历循环)在调用它们时都使用orig_foo
的全局值。所以他们都叫B.foo(self)
。
当调用像orig_foo
这样的“未绑定方法”时,Python2会检查第一个参数是否是相应类的实例。 A().foo()
未通过此检查。 (有趣的是,这个检查在Python3中被删除了,因此不会引发TypeError,并且这个bug可能变得更难找到。)
要解决此问题,您必须将orig_foo
的值绑定到相应的klass
。
您可以通过将orig_foo
设置为foo
的局部变量来实现。一种方法是使orig_foo
成为foo
的参数,并使用默认值。 Python在定义函数时绑定默认值。因此orig_foo=orig_foo
将局部变量orig_foo
绑定到klass.foo
的当前值:
for klass in A, B:
orig_foo = klass.foo
def foo(self, orig_foo=orig_foo):
return orig_foo(self) * 2
klass.foo = foo