python3:使用.__get__()将方法绑定到类实例,为什么有效?
我知道,如果你想给一个类的实例添加一个方法,不能简单地像这样赋值:
>>> 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
并返回结果。