简体   繁体   English

为什么可以通过描述符引入 __slots__?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM