Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么通过描述符可以引入“插槽”?_Python_Slots_Python Descriptors - Fatal编程技术网

Python 为什么通过描述符可以引入“插槽”?

Python 为什么通过描述符可以引入“插槽”?,python,slots,python-descriptors,Python,Slots,Python Descriptors,在“Python的历史”系列中,Guido van Rossum指出: 描述符的另一个增强是在类上引入了_slots____)属性 我把这句话理解为:引擎盖下的插槽由描述符实现 但与我的解释相反,Guido van Rossum后来写了几行: 在封面下,这个特性的实现完全是用C语言完成的,而且效率很高 那么,插槽不是由描述符实现的 但两句话之后,他又写道: 不仅是一个有趣的描述符应用 那么,插槽和描述符的实际情况是什么 插槽是否由描述符实现?如果是:如何做?考虑一个简单的类: class A:

在“Python的历史”系列中,Guido van Rossum指出:

描述符的另一个增强是在类上引入了_slots____)属性

我把这句话理解为:引擎盖下的插槽由描述符实现

但与我的解释相反,Guido van Rossum后来写了几行:

在封面下,这个特性的实现完全是用C语言完成的,而且效率很高

那么,插槽不是由描述符实现的

但两句话之后,他又写道:

不仅是一个有趣的描述符应用

那么,插槽和描述符的实际情况是什么


插槽是否由描述符实现?如果是:如何做?

考虑一个简单的类:

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