Python中的“插槽包装器”是什么?
object.__dict__
和其他一些地方有一些隐藏的方法,它们被设置成像这样的东西:
<dictproxy {'__add__': <slot wrapper '__add__' of 'instance' objects>,
'__and__': <slot wrapper '__and__' of 'instance' objects>,
'__call__': <slot wrapper '__call__' of 'instance' objects>,
'__cmp__': <slot wrapper '__cmp__' of 'instance' objects>,
'__coerce__': <slot wrapper '__coerce__' of 'instance' objects>,
'__contains__': <slot wrapper '__contains__' of 'instance' objects>,
'__delattr__': <slot wrapper '__delattr__' of 'instance' objects>,
'__delitem__': <slot wrapper '__delitem__' of 'instance' objects>,
'__delslice__': <slot wrapper '__delslice__' of 'instance' objects>,
'__div__': <slot wrapper '__div__' of 'instance' objects>,
'__divmod__': <slot wrapper '__divmod__' of 'instance' objects>,
...
这些是什么?它们有什么用?
补充说明:
这是来自于:
class A:
pass
b = A()
print(type(b).__dict__)
3 个回答
0
这是一种内部类型,用于一些可调用的对象,比如内置类的方法。其实它和普通函数或者其他可调用对象有什么不同并不重要。你可以像调用对象的方法一样来使用它。
2
在Python中,object
类是所有类的基础类。可以推测,它的底层代码是为了性能而优化的。
在CPython中,Python的实现是用C和Python两种语言写的。底层代码用C语言编写,以满足性能需求。
那么,从Python脚本调用一个在某个C编译的二进制文件中的函数指针是怎么处理的呢?
举个例子,调用repr(b)
时,逻辑大致是这样的:
- 首先检查
b.__dict__
中是否有绑定方法的名字__repr__
,如果有,就尝试调用它。 - 如果没有找到,就去它的类
type(b).__dict__
中查找,相当于去找A.__dict__
。 - 如果还是没找到,就会在它的父类中查找。
A.__base__
在这里就是object
类。由于hasattr(object, '__repr__')==True
,所以最终会找到并返回绑定方法object.__repr__
,这个方法是一个包装器,它是wrapper_descriptor
类的一个实例。 - 这个包装器会处理必要的事情,比如获取对象b的详细信息、获取C函数的指针、传递必要的参数、处理异常和错误等等。
所以,这其实是一个包装器,它利用CPython自己的API来处理内置函数,帮我们省去麻烦,并将两种语言的逻辑分开。
最后一个例子,展示了同一个调用两次:
>>> object.__repr__(b)
'<__main__.A object at 0x011EE5C8>'
>>> repr(b)
'<__main__.A object at 0x011EE5C8>'
3
根据这个链接的介绍:
槽包装器是用来在一个扩展类型的字典里,访问用C语言实现的特殊方法的。比如说,像object.__init__或者Integer.__lt__这样的例子。需要注意的是,槽包装器总是没有绑定的(还有一种叫做方法包装器的绑定变体)。
所以,它们实际上就是一些方法,用来包装那些用C语言实现的对象方法。在Python中,很多魔法方法和属性都是通过这些槽包装器来实现的,因为大多数Python的实现都是用C语言写的,这样的设计是很合理的。