[英]Why the introduction of __slots__ was made possible with descriptors?
In this blog post from the series "The History of Python", Guido van Rossum states:在“Python 的历史”系列的这篇博文中,Guido van Rossum 说:
Another enhancement made possible with descriptors was the introduction of the __slots__ attribute on classes.描述符的另一个增强是在类上引入了 __slots__ 属性。
I understand this sentence as: under the hood __slots__ is implemented by descriptors.我将这句话理解为:在引擎盖下 __slots__ 是由描述符实现的。
But contrary to this my interpretation, Guido van Rossum writes a few lines later:但与我的解释相反,Guido van Rossum 在几行之后写道:
Underneath the covers, the implementation of this feature is done entirely in C and is highly efficient.在幕后,此功能的实现完全用 C 语言完成,并且非常高效。
So, __slots__ is not implemented by descriptors?那么,__slots__ 不是由描述符实现的吗?
But two sentences later, again he writes:但是两句话之后,他又写道:
Not only was __slots__ an interesting application of descriptors, ... __slots__ 不仅是一个有趣的描述符应用,......
So, what's actually the case with __slots__ and descriptors?那么,__slots__ 和描述符的实际情况是什么?
Is __slots__ implemented by descriptors or not? __slots__ 是否由描述符实现? And if yes: how?如果是:如何?
The statements don't contradict themselves.这些陈述并不自相矛盾。 The attributes defined by __slots__
are descriptors on the created class and the implementation of that descriptor is written in C (assuming CPython).通过定义的属性__slots__
是所创建的类和描述符的描述符的实施是用C(假定CPython的)。
The descriptor class is called member_descriptor
as can be seen by this example code:描述符类称为member_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
And a quick search on the CPython repository on GitHub revealed the C implementation of it (Link for CPython version 3.8.0) .对 GitHub 上的 CPython 存储库进行快速搜索,发现了它的 C 实现(CPython 版本 3.8.0 的链接) 。
To go into a bit more detail:更详细一点:
A Python class is essentially a dict
with (a lot of) bells and whistles. Python 类本质上是一个带有(很多)花里胡哨的dict
。 On the other hand there are Python-C-classes that use a C- struct
to implement a Python class.另一方面,Python-C-classes 使用 C- struct
来实现 Python 类。 Such a C-struct is faster and requires (significantly) less memory than a dictionary even if it only contains Python objects (which is basically a C-array containing references to Python objects).即使它只包含 Python 对象(基本上是一个包含对 Python 对象的引用的 C 数组),这样的 C 结构更快,并且比字典需要(显着)更少的内存。
To make it possible that "normal" Python classes could benefit from the faster access and the reduced memory footprint __slots__
was introduced.为了使“普通”Python 类可以从更快的访问和减少的内存占用中受益,引入了__slots__
。 A class with __slots__
will be translated essentially to a C-struct.带有__slots__
的类将基本上被转换为 C 结构。 However to make it possible that the attribute lookup/setting/deletion map to the corresponding struct
member some sort of translation layer (descriptors) is required.然而,为了使属性查找/设置/删除映射到相应的struct
成员成为可能,需要某种翻译层(描述符)。 That translation layer for members defined in __slots__
is member_descriptor
. __slots__
定义的成员的翻译层是member_descriptor
。
So when you look up the attribute on an instance of a __slots__
-class you'll get a member_descriptor
and that member_descriptor
will know how to get/set/delete the member of the underlying C- struct
.因此,当您在__slots__
-class 的实例上查找属性时,您将获得一个member_descriptor
并且该member_descriptor
将知道如何获取/设置/删除底层 C- struct
的成员。
Consider a simple class:考虑一个简单的类:
class A:
__slots__ = ('a',)
What is a
?什么是a
? It's a descriptor:这是一个描述符:
>>> type(A.a)
<class 'member_descriptor'>
Each string in the value of __slots__
is used to create a class attribute by that name with a member_descriptor
value. __slots__
值中的每个字符串用于通过该名称创建一个具有member_descriptor
值的类属性。
That means you can (try to) access it via Aa__get__
这意味着您可以(尝试)通过Aa__get__
访问它
>>> a = A()
>>> a.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: a
assign to it with Aa__set__
用Aa__set__
分配给它
>>> a.a = 7
and try to access it again :)并尝试再次访问它:)
>>> a.a
7
What you can't do is try to assign to any other attribute on the instance:您不能做的是尝试分配给实例上的任何其他属性:
>>> 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'
The presence of __slots__
not only creates the requested class attributes, but prevents the creation of any additional attributes on an instance. __slots__
的存在不仅会创建请求的类属性,还会阻止在实例上创建任何其他属性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.