【问题标题】:How do the __slot__ descriptors work in python?__slot__ 描述符如何在 python 中工作?
【发布时间】:2018-06-08 03:49:03
【问题描述】:

我知道__slots__ 的作用和用途。

但是,我还没有找到关于使用 __slots__ 创建的 member 描述符的底层机制如何工作的全面答案。

对象级值实际存储在哪里?

有没有办法在不直接访问描述符的情况下更改这些值?
(例如,当 C 类具有 __dict__ 时,您可以使用 C.__dict__['key'] 而不是 C.key

可以通过创建类似的类级描述符来“扩展”定义__slots__ 的对象的不变性吗?作为对此的进一步阐述;可以使用元类构建不可变对象,但不通过手动创建所述描述符来显式定义__slots__

【问题讨论】:

    标签: python immutability metaclass slots python-descriptors


    【解决方案1】:

    __slot__ 属性在对象的本机内存表示中分配,然后与访问的类关联的描述符实际上使用 CPython 中的本机 C 方法来设置和检索对归因于每个插槽属性的 Python 对象的引用在类实例上作为 C 结构。

    在 Python 中以名称 member_descriptor 表示的插槽描述符在此处定义:https://github.com/python/cpython/blob/master/Objects/descrobject.c

    如果不使用 CType 与本机代码交互,无论如何您都无法从纯 Python 代码执行或增强这些描述符。

    可以通过执行类似的操作来获取他们的类型

    class A:
       __slots__ = "a"
    
    member_descriptor = type(A.a)
    

    然后可以假设可以从它继承,并编写派生的 __get____set__ 方法来执行检查等 - 但不幸的是,它不能作为基类工作。

    但是,可以编写其他并行的描述符,这些描述符又可以调用本机描述符来实际存储值。 通过使用元类,可以在类创建时重命名传入的 __slots__ 并将其访问权限包装在可以执行额外检查的自定义描述符中 - 甚至可以从“dir”中隐藏。

    因此,对于一个简单的类型检查槽变体元类,可以有

    class TypedSlot:
        def __init__(self, name, type_):
            self.name = name
            self.type = type_
    
        def __get__(self, instance, owner):
            if not instance:
                return self
            return getattr(instance, "_" + self.name)
    
        def __set__(self, instance, value):
            if not isinstance(value, self.type):
                raise TypeError
            setattr(instance, "_" + self.name, value)
    
    
    class M(type):
        def __new__(metacls, name, bases, namespace):
            new_slots = []
            for key, type_ in namespace.get("__slots__", {}).items():
                namespace[key] = TypedSlot(key, type_)
                new_slots.append("_" + key)
            namespace["__slots__"] = new_slots
            return super().__new__(metacls, name, bases, namespace)
    
        def __dir__(cls):
            return [name for name in super().__dir__() if  name not in cls.__slots__]
    

    【讨论】:

      猜你喜欢
      • 2011-10-28
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      • 2011-01-14
      • 1970-01-01
      • 2019-11-11
      • 2011-04-28
      相关资源
      最近更新 更多