首页 > 解决方案 > 为什么使用描述符可以引入 __slots__?

问题描述

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

描述符的另一个增强功能是在类中引入了 __slots__ 属性。

我将这句话理解为:在引擎盖下 __slots__ 是由描述符实现的。

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

在幕后,此功能的实现完全在 C 中完成,并且非常高效。

那么,__slots__ 不是由描述符实现的吗?

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

__slots__ 不仅是描述符的有趣应用,...

那么,__slots__ 和描述符的实际情况是什么?

__slots__ 是否由描述符实现?如果是的话:如何?

标签: pythonslotspython-descriptors

解决方案


这些陈述并不自相矛盾。定义的属性__slots__是所创建类的描述符,并且该描述符的实现是用 C 编写的(假设是 CPython)。

描述符类被调用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

在 GitHub 上的 CPython 存储库上快速搜索发现了它的 C 实现(CPython 版本 3.8.0 的链接)


更详细一点:

Python 类本质上是一个dict带有(很多)花里胡哨的东西。另一方面,有一些 Python-C 类使用 C-struct来实现 Python 类。这样的 C 结构比字典更快并且需要(显着)更少的内存,即使它只包含 Python 对象(基本上是一个包含对 Python 对象的引用的 C 数组)。

为了使“普通”Python 类可以受益于更快的访问和减少的内存占用__slots__。一个类__slots__将本质上转换为一个 C 结构。然而,为了使属性查找/设置/删除映射到相应的struct成员成为可能,需要某种翻译层(描述符)。中定义的成员的翻译层__slots__member_descriptor.

__slots__因此,当您在-class的实例上查找属性时,您将获得 amember_descriptor并且member_descriptor它将知道如何获取/设置/删除基础 C- 的成员struct


推荐阅读