Python 为什么通过描述符可以引入“插槽”?
在“Python的历史”系列中,Guido van Rossum指出: 描述符的另一个增强是在类上引入了_slots____)属性 我把这句话理解为:引擎盖下的插槽由描述符实现 但与我的解释相反,Guido van Rossum后来写了几行: 在封面下,这个特性的实现完全是用C语言完成的,而且效率很高 那么,插槽不是由描述符实现的 但两句话之后,他又写道: 不仅是一个有趣的描述符应用 那么,插槽和描述符的实际情况是什么Python 为什么通过描述符可以引入“插槽”?,python,slots,python-descriptors,Python,Slots,Python Descriptors,在“Python的历史”系列中,Guido van Rossum指出: 描述符的另一个增强是在类上引入了_slots____)属性 我把这句话理解为:引擎盖下的插槽由描述符实现 但与我的解释相反,Guido van Rossum后来写了几行: 在封面下,这个特性的实现完全是用C语言完成的,而且效率很高 那么,插槽不是由描述符实现的 但两句话之后,他又写道: 不仅是一个有趣的描述符应用 那么,插槽和描述符的实际情况是什么 插槽是否由描述符实现?如果是:如何做?考虑一个简单的类: class A:
插槽是否由描述符实现?如果是:如何做?考虑一个简单的类:
class A:
__slots__ = ('a',)
什么是a
?这是一个描述符:
>>> type(A.a)
<class 'member_descriptor'>
用A.A.\uuuu set\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
>>> a = A()
>>> a.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: a
>>> a.a = 7
然后再次尝试访问它:)
您不能做的是尝试分配给实例上的任何其他属性:
>>> A.b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'A' has no attribute 'b'
>>> a.b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'b'
>>> a.b = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'b'
>>A.b
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:类型对象“A”没有属性“b”
>>>a.b
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:“A”对象没有属性“b”
>>>a.b=0
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
AttributeError:“A”对象没有属性“b”
\uuuuuuuuuuuuuuuuuuuu>的存在不仅会创建请求的类属性,而且会阻止在实例上创建任何附加属性。这些语句本身并不矛盾。\uuuuuuuuuuuuuuuuuuuuuuu
定义的属性是所创建类上的描述符,该描述符的实现是用C编写的(假设是CPython)
描述符类被称为member\u descriptor
,如下面的示例代码所示:
import inspect
class Test:
__slots__ = 'a',
def __init__(self, a):
self.a = a
type(Test.a) # member_descriptor
inspect.isdatadescriptor(Test.a) # True
inspect.ismemberdescriptor(Test.a) # True
在GitHub上的CPython存储库上进行快速搜索
更详细地说:
Python类本质上是一个带有(许多)铃铛和哨子的dict
。另一方面,有些Python-C类使用C-struct
来实现Python类。这样的C-struct比字典更快,所需内存(明显)更少,即使它只包含Python对象(基本上是包含Python对象引用的C-array)
为了使“普通”Python类能够从更快的访问和减少的内存占用中获益,引入了\uuuuuu slots\uuuu
。带有\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu插槽的类基本上将被转换为C结构。但是,为了使属性查找/设置/删除映射到相应的struct
成员,需要某种类型的转换层(描述符)。在中定义的成员的转换层是成员描述符
因此,当您在\uuu slots\uuu
-类的实例上查找属性时,您将得到一个成员描述符
,而成员描述符
将知道如何获取/设置/删除底层C-结构的成员
import inspect
class Test:
__slots__ = 'a',
def __init__(self, a):
self.a = a
type(Test.a) # member_descriptor
inspect.isdatadescriptor(Test.a) # True
inspect.ismemberdescriptor(Test.a) # True