为什么猴子补丁方法不传实例引用?

10 投票
2 回答
1314 浏览
提问于 2025-04-18 02:45

这里有一个示例来演示:

>>> class M:
       def __init__(self): self.x = 4
>>> sample = M()
>>> def test(self):
        print(self.x)
>>> sample.test = test
>>> sample.test()
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    sample.test()
TypeError: test() missing 1 required positional argument: 'self'

为什么呢?

2 个回答

2

函数其实和其他对象一样,都是对象。无论这些对象的名字在哪里(比如在本地命名空间里,或者作为某个对象的属性),它们的赋值过程都应该保持一致。

当你用 def 来定义一个函数时,你就是把这个函数和 def 后面的名字绑定在一起。而当你做类似 some_object.f = my_function 的赋值时,你也是在把这个函数和一个名字绑定在一起。这个赋值过程没有什么神奇之处,它不会改变函数的本质。

不过,在类定义的过程中确实有一些特别的地方。作为实例方法定义的函数(也就是在类定义内部定义的函数),并不是简单地作为属性赋值给实例,而是通过一种叫做 描述符 的机制来绑定到实例上。

18

你给 sample.test 赋值的 test 方法并没有和 sample 这个对象绑定在一起。你需要手动把它绑定,像这样做:

import types
sample.test = types.MethodType(test, sample)
sample.test()
# 4

撰写回答