gpt4 book ai didi

python - __slot__ 描述符如何在 python 中工作?

转载 作者:太空宇宙 更新时间:2023-11-03 15:48:55 25 4
gpt4 key购买 nike

我知道 __slots__ 的作用以及它的用途。

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

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

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

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

最佳答案

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

槽的描述符,在 Python 中以名称 member_descriptor 定义在这里:https://github.com/python/cpython/blob/master/Objects/descrobject.c

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

可以通过做类似的事情来获得他们的类型

class A:
__slots__ = "a"

member_descriptor = type(A.a)

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

但是,可以编写其他并行的描述符,这些描述符又可以调用 native 描述符来实际存储值。通过使用元类,可以在类创建时重命名传入的 __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__]

关于python - __slot__ 描述符如何在 python 中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47993203/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com