gpt4 book ai didi

python - 如何动态更改 __slots__ 属性?

转载 作者:太空狗 更新时间:2023-10-30 01:37:55 25 4
gpt4 key购买 nike

假设我有一个 __slots__ 的类(class)

class A:
__slots__ = ['x']

a = A()
a.x = 1 # works fine
a.y = 1 # AttributeError (as expected)

现在我要改__slots__A .

A.__slots__.append('y')
print(A.__slots__) # ['x', 'y']
b = A()
b.x = 1 # OK
b.y = 1 # AttributeError (why?)

b创建于 __slots__ 之后的 A已经改变,所以 Python 原则上可以为 b.y 分配内存。 .为什么没有?

如何正确修改__slots__一个类,以便新实例具有修改后的属性?

最佳答案

您不能在创建类后动态更改 __slots__ 属性,不行。那是因为该值用于创建特殊的 descriptors对于每个插槽。来自__slots__ documentation :

__slots__ are implemented at the class level by creating descriptors (Implementing Descriptors) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.

可以看到类__dict__中的描述符:

>>> class A:
... __slots__ = ['x']
...
>>> A.__dict__
mappingproxy({'__module__': '__main__', '__doc__': None, 'x': <member 'x' of 'A' objects>, '__slots__': ['x']})
>>> A.__dict__['x']
<member 'x' of 'A' objects>
>>> a = A()
>>> A.__dict__['x'].__get__(a, A)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: x
>>> A.__dict__['x'].__set__(a, 'foobar')
>>> A.__dict__['x'].__get__(a, A)
'foobar'
>>> a.x
'foobar'

您不能自己创建这些额外的描述符。即使可以,您也不能为此类生成的实例上的额外槽引用分配更多内存空间,因为这些信息存储在该类的 C 结构中,而不是以 Python 代码可访问的方式。

那是因为 __slots__ 只是对构成 Python 实例的元素的低级处理对 Python 代码的扩展; 常规 Python 实例上的 __dict____weakref__ 属性始终作为插槽实现:

>>> class Regular: pass
...
>>> Regular.__dict__['__dict__']
<attribute '__dict__' of 'Regular' objects>
>>> Regular.__dict__['__weakref__']
<attribute '__weakref__' of 'Regular' objects>
>>> r = Regular()
>>> Regular.__dict__['__dict__'].__get__(r, Regular) is r.__dict__
True

所有 Python 开发人员在这里所做的就是扩展系统以使用任意名称添加更多这样的插槽,这些名称取自正在创建的类的 __slots__ 属性,这样您就可以保存内存;字典比对槽中值的简单引用占用更多的内存。通过指定 __slots__,您可以禁用 __dict____weakref__ 槽,除非您明确地将它们包含在 __slots__ 序列中。

扩展插槽的唯一方法是子类化;您可以使用 type() 函数或使用工厂函数动态创建子类:

def extra_slots_subclass(base, *slots):
class ExtraSlots(base):
__slots__ = slots
ExtraSlots.__name__ = base.__name__
return ExtraSlots

关于python - 如何动态更改 __slots__ 属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30746356/

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