python3:使用.__get__()将方法绑定到类实例,为什么有效?

10 投票
1 回答
3948 浏览
提问于 2025-04-17 02:43

我知道,如果你想给一个类的实例添加一个方法,不能简单地像这样赋值:

>>> def print_var(self): # method to be added
        print(self.var)
>>> class MyClass:
        var = 5
>>> c = MyClass()
>>> c.print_var = print_var

这样做确实会让 print_var 像普通函数一样工作,这样 self 参数就不会有它通常的意义了:

>>> c.print_var
<function print_var at 0x98e86ec>
>>> c.print_var()
Traceback (most recent call last):
  File "<pyshell#149>", line 1, in <module>
    c.print_var()
TypeError: print_var() takes exactly 1 argument (0 given)

为了让这个函数被视为一个方法(也就是绑定到实例上),我以前会使用这段代码:

>>> import types
>>> c.print_var = types.MethodType(print_var, c)
>>> c.print_var
<bound method MyClass.print_var of <__main__.MyClass object at 0x98a1bac>>
>>> c.print_var()
5

但我发现 .__get__ 也可以用来达到这个目的:

>>> c.print_var = print_var.__get__(c)
>>> c.print_var
<bound method MyClass.print_var of <__main__.MyClass object at 0x98a1bac>>
>>> c.print_var()
5

这里的问题是,它虽然能工作,但我不明白为什么会这样。关于 .__get__ 的文档似乎也没有太多帮助。

如果有人能解释一下 Python 解释器的这种行为,我会很感激。

1 个回答

9

你想要的信息在这个描述符使用指南里:

为了支持方法调用,函数里有一个叫做 __get__() 的方法,用于在访问属性时绑定方法。这意味着所有的函数都是非数据描述符,根据你是从对象还是类调用它们,会返回绑定的方法或未绑定的方法。在纯Python中,它是这样工作的:

class Function(object):
    . . .
    def __get__(self, obj, objtype=None):
        "Simulate func_descr_get() in Objects/funcobject.c"
        return types.MethodType(self, obj)

所以其实没有什么奇怪的事情发生——函数对象的 __get__ 方法调用了 types.MethodType 并返回结果。

撰写回答