我正在编写一个使用内省找到类的"未绑定方法"的代码,并且惊讶地发现内置类型有两种不同的描述符:
>>> type(list.append), list.append
(<class 'method_descriptor'>, <method 'append' of 'list' objects>)
>>> type(list.__add__), list.__add__
(<class 'wrapper_descriptor'>, <slot wrapper '__add__' of 'list' objects>)
Run Code Online (Sandbox Code Playgroud)
搜索文档非常有限但有趣的结果:
inspect.getattr_static它不解析描述符并包含可用于解析它们的代码.method_descriptor是更有效的比wrapper_descriptor,但是不解释它们是什么:
的方法
list.__getitem__(),dict.__getitem__()和dict.__contains__()现在被实现为method_descriptor对象,而不是wrapper_descriptor对象.这种访问形式使其性能翻倍,并使它们更适合用作功能的参数:map(mydict.__getitem__, keylist).
性能上的差异引起了我的兴趣,显然存在差异所以我去寻找其他信息.
这些类型都不在模块中types:
>>> import types
>>> type(list.append) in vars(types).values()
False
>>> type(list.__add__) in vars(types).values()
False
Run Code Online (Sandbox Code Playgroud)
使用help不提供任何有用的信息:
>>> help(type(list.append))
Help on class method_descriptor in module builtins:
class method_descriptor(object)
| Methods defined here:
|
<generic descriptions for>
__call__, __get__, __getattribute__, __reduce__, and __repr__
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __objclass__
|
| __text_signature__
>>> help(type(list.__add__))
Help on class wrapper_descriptor in module builtins:
class wrapper_descriptor(object)
| Methods defined here:
|
<generic descriptions for>
__call__, __get__, __getattribute__, __reduce__, and __repr__
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __objclass__
|
| __text_signature__
Run Code Online (Sandbox Code Playgroud)
在互联网上搜索只得到关于"什么是描述符"的结果或对所涉及的特定类型的模糊引用.
所以我的问题是:
<class 'method_descriptor'>和之间的实际区别是<class 'wrapper_descriptor'>什么?
这是一个实施细节。在 C 级别,内置类型通过结构数组按名称list定义方法,而特殊方法则更间接地定义。appendPyMethodDef__add__
__add__sq_concat对应于类型的tp_as_sequence或nb_add类型的两个槽中的任意一个中的函数指针tp_as_number。如果某个类型定义了其中一个槽,Python 会wrapper_descriptor为__add__Python 级 API 的方法生成该槽的包装。
类型槽和结构所需的包装PyMethodDef有点不同;例如,两个槽可以对应一种方法,或者一个槽可以对应六种方法。插槽也不带有方法名称,而方法名称是PyMethodDef. 由于这两种情况需要不同的代码,Python 使用不同的包装器类型来包装它们。
如果您想查看代码, 和 都method_descriptor在wrapper_descriptor中实现Objects/descrobject.c,其中 struct typedef 在 中Include/descrobject.h。您可以在 中看到初始化包装器的代码Objects/typeobject.c,其中PyType_Ready委托给add_operatorsfor wrapper_descriptors 和add_methodsfor method_descriptors。