假设我有一个__slots__
的类
class A:
__slots__ = ['x']
a = A()
a.x = 1 # works fine
a.y = 1 # AttributeError (as expected)
现在我要改变{
A.__slots__.append('y')
print(A.__slots__) # ['x', 'y']
b = A()
b.x = 1 # OK
b.y = 1 # AttributeError (why?)
b
是在A
中的__slots__
发生更改后创建的,因此Python原则上可以为b.y
分配内存。为什么没有
如何正确修改类的__slots__
,以便新实例具有修改后的属性
不能在创建类之后动态更改} documentation 开始:
__slots__
属性。这是因为该值用于为每个插槽创建特殊的descriptors。从^{您可以在类
__dict__
中看到描述符:您不能自己创建这些附加描述符。即使可以,也不能为该类生成的实例上的额外插槽引用分配更多的内存空间,因为这是存储在该类的C结构中的信息,而不是以Python代码可以访问的方式
这一切都是因为
__slots__
只是Python代码中组成Python实例的元素的低级处理的扩展;常规Python实例上的__dict__
和__weakref__
属性始终作为插槽实现:Python开发人员在这里所做的全部工作就是扩展系统,使用任意名称添加更多此类插槽,这些名称取自所创建类的
__slots__
属性,以便节省内存;字典比插槽中的值的简单引用占用更多内存。通过指定__slots__
,可以禁用__dict__
和__weakref__
插槽,除非在__slots__
序列中显式包含这些插槽扩展槽的唯一方法是子类;您可以使用
type()
函数或使用工厂函数动态创建子类:在我看来a type turns ^{} into a tuple as one of it's first orders of action 。然后是stores the tuple on the extended type object。因为在这一切之下,python正在寻找一个
tuple
,所以没有办法对它进行变异。事实上,我甚至不确定您是否可以访问它,除非您首先向实例传递一个元组您设置的原始对象仍然作为类型的一个属性保留(也许)只是一种方便的内省
您不能修改
__slots__
并期望它在某个地方出现(而且真的--从可读性的角度来看,您可能并不真的想这样做,对吧?)当然,您始终可以使用子类来扩展插槽:
创建类后不能修改
__slots__
属性。这是因为它会导致奇怪的行为想象一下下面的情景
在这种情况下会发生什么?最初没有为第二个插槽分配空间,但是根据slots属性,
a
应该能够为y
分配空间__slots__
并不是保护可以访问和不能访问的名称。相反__slots__
是关于减少对象的内存占用。通过尝试修改__slots__
,您将无法实现__slots__
想要实现的优化插槽如何减少内存占用
通常,对象的属性存储在
dict
中,这本身就需要相当多的内存。如果要创建数百万个对象,则这些命令所需的空间将变得不可接受__slots__
通知生成类对象的python机制,该类的实例引用的属性将非常多,属性的名称将是什么。因此,该类可以通过将属性直接存储在实例上而不是存储在dict
中来进行优化。它将(指向的指针)属性的内存直接放在对象上,而不是为对象创建一个新的dict
相关问题 更多 >
编程相关推荐