猴子补丁方法和参考的问题

发布于 2024-12-01 11:22:40 字数 673 浏览 0 评论 0原文

我想知道是否有人可以解释并提供此问题的解决方案:

$ 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)

提前致谢。

I was wondering if anyone could explain and offer a solution to this issue:

$ 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)

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初懵 2024-12-08 11:22:40

orig_foo 是一个全局变量,每次通过循环都会改变值。循环完成后,orig_foo 引用B.foo

内部函数 foo(一个或每个通过循环)在调用时都使用 orig_foo 的全局值。所以他们都调用B.foo(self)

当调用像orig_foo这样的“未绑定方法”时,Python2会检查第一个参数是否是适当类的实例。 A().foo() 未通过此检查。 (有趣的是,这个检查在 Python3 中被删除,因此不会引发 TypeError,并且这个 bug 可能会变得更难发现。)

要解决这个问题,您必须将 orig_foo 的值绑定到适当的 <代码>类。
您可以通过将 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

orig_foo is a global variable which changes value with each pass through the loop. After the loop is done, orig_foo refers to B.foo.

The inner functions foo (one or each pass through the loop) both use the global value for orig_foo when they are called. So they both call B.foo(self).

When calling an "unbound method" like orig_foo, Python2 checks that the first argument is an instance of the appropriate class. A().foo() does not pass this check. (Interestingly, this check was removed in Python3, so there would be no TypeError raised, and this bug may become harder to find.)

To fix this, you must bind the value of orig_foo to the appropriate klass.
You can do that by making orig_foo a local variable of foo. One way to do that is to make orig_foo an argument of foo with a default value. Python binds default values at the time a function is defined. So orig_foo=orig_foo binds the local variable orig_foo to the current value of the 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
一杆小烟枪 2024-12-08 11:22:40

因为 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 值。

Because orig_foo is defined at global scope, you're trampling on its value each time round the loop. That trampled value is then shared by each of your new foo methods.

A simple fix is to move the code into a function, like this:

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)

That ensures that each new foo method gets its own value of orig_foo.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文