Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.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_Immutability_Metaclass_Slots_Python Descriptors - Fatal编程技术网

在python中,槽描述符是如何工作的?

在python中,槽描述符是如何工作的?,python,immutability,metaclass,slots,python-descriptors,Python,Immutability,Metaclass,Slots,Python Descriptors,我知道插槽的功能和它的用途 然而,对于使用\uuuuu插槽创建的成员描述符的底层机制如何工作,我还没有找到一个全面的答案 对象级别的值实际存储在哪里 有没有办法在不直接访问描述符的情况下更改这些值? (例如,当类C具有\uuuuu dict\uuuuu时,您可以执行C.\uuuu dict\uuuu['key']而不是C.key) 通过创建类似的类级描述符,可以“扩展”定义\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

我知道插槽的功能和它的用途

然而,对于使用
\uuuuu插槽
创建的
成员
描述符的底层机制如何工作,我还没有找到一个全面的答案

对象级别的值实际存储在哪里

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


通过创建类似的类级描述符,可以“扩展”定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?并作进一步阐述,;是否可以使用元类构建一个不可变的对象,但不通过手动创建所述描述符来明确定义
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,与访问的类相关联的描述符实际上使用CPython中的本机C方法来设置和检索作为C结构的类实例上每个slot属性的Python对象的引用

用Python表示的插槽描述符,名称为
member\u descriptor
,定义如下:

如果不使用CTypes与本机代码交互,就无法从纯Python代码中执行或增强这些描述符

有可能通过以下方式达到他们的类型

class A:
   __slots__ = "a"

member_descriptor = type(A.a)
然后我们可以假设可以从它继承,并编写派生的
\uuuuu get\uuuu
\uuuu set\uuuuu
方法,这些方法可以进行检查等等,但不幸的是,它不能作为基类工作

但是,可以编写其他并行描述符,这些描述符可以调用本机描述符来实际存储值。 通过使用元类,可以在类创建时重命名传入的
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
并将它们的访问权封装在自定义描述符中

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

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__]