函数描述符是如何工作的?
How do function descriptors work?
我在阅读 a presentation 关于 Python 的对象模型时,在一张幻灯片(第 9
号)中,作者断言 Python 的功能是描述符。他提供的例子与我写的这个相似:
def mul(x, y):
return x * y
mul2 = mul.__get__(2)
mul2(3) # 6
现在,我明白了这一点,因为该函数定义了一个 __get__
它是一个描述符,正如我在 Python 文档的描述部分中所描述的那样。
我不明白的是所提供的输出中的调用结果究竟如何。
这就是 Python 所做的,以支持向 classes 动态添加功能。
当在函数对象上调用 __get__
时(通常通过点访问 .
在 class 的实例上完成)Python 会将函数转换为method 和 implicitly 将实例(通常识别为 self
)作为第一个参数传递。
在你的例子中,你显式调用__get__
并且显式传递'instance'2
绑定为函数 x
的第一个参数,这里 2
被认为是 "instance" self
:
>>> mul2
<bound method mul of 2>
这导致方法绑定在实例 2 上,有一个产生乘法的预期参数:调用它 returns 2
(分配给 x
的绑定参数)相乘与您提供的任何其他内容作为参数 y
.
通常,function()
使用提供的适当参数调用它的 __call__
:
mul.__call__(2, 3) # 6
另外,Python 文档的 Descriptor HOWTO 文档中提供了 __get__
函数的 Python 实现。
在这里您可以看到调用 __get__
时发生的使用 types.MethodType
的转换:
class Function(object):
. . .
def __get__(self, obj, objtype=None):
"Simulate func_descr_get() in Objects/funcobject.c"
return types.MethodType(self, obj, objtype)
感兴趣的访客的源代码位于 Objects/funcobject.c
。
如您所见,如果此描述符不存在,您必须在任何时候自动将函数包装在 types.MethodType
中,以便将函数动态添加到 class,这是不必要的麻烦。
我在阅读 a presentation 关于 Python 的对象模型时,在一张幻灯片(第 9
号)中,作者断言 Python 的功能是描述符。他提供的例子与我写的这个相似:
def mul(x, y):
return x * y
mul2 = mul.__get__(2)
mul2(3) # 6
现在,我明白了这一点,因为该函数定义了一个 __get__
它是一个描述符,正如我在 Python 文档的描述部分中所描述的那样。
我不明白的是所提供的输出中的调用结果究竟如何。
这就是 Python 所做的,以支持向 classes 动态添加功能。
当在函数对象上调用 __get__
时(通常通过点访问 .
在 class 的实例上完成)Python 会将函数转换为method 和 implicitly 将实例(通常识别为 self
)作为第一个参数传递。
在你的例子中,你显式调用__get__
并且显式传递'instance'2
绑定为函数 x
的第一个参数,这里 2
被认为是 "instance" self
:
>>> mul2
<bound method mul of 2>
这导致方法绑定在实例 2 上,有一个产生乘法的预期参数:调用它 returns 2
(分配给 x
的绑定参数)相乘与您提供的任何其他内容作为参数 y
.
通常,function()
使用提供的适当参数调用它的 __call__
:
mul.__call__(2, 3) # 6
另外,Python 文档的 Descriptor HOWTO 文档中提供了 __get__
函数的 Python 实现。
在这里您可以看到调用 __get__
时发生的使用 types.MethodType
的转换:
class Function(object):
. . .
def __get__(self, obj, objtype=None):
"Simulate func_descr_get() in Objects/funcobject.c"
return types.MethodType(self, obj, objtype)
感兴趣的访客的源代码位于 Objects/funcobject.c
。
如您所见,如果此描述符不存在,您必须在任何时候自动将函数包装在 types.MethodType
中,以便将函数动态添加到 class,这是不必要的麻烦。