我想知道是否有人可以解释并提供这个问题的解决方案:
$ 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)提前谢谢。
发布于 2011-08-26 21:25:46
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发布于 2011-08-26 21:21:30
因为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值。
https://stackoverflow.com/questions/7205180
复制相似问题