我有一棵拥有数十万个节点的大树,而我正在使用__slots__
来减少内存消耗。我刚刚发现了一个非常奇怪的错误并修复了它,但我不明白我看到的行为。
这是一个简化的代码示例:
class NodeBase(object):
__slots__ = ["name"]
def __init__(self, name):
self.name = name
class NodeTypeA(NodeBase):
name = "Brian"
__slots__ = ["foo"]
然后执行以下命令:
>>> node = NodeTypeA("Monty")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __init__
AttributeError: 'NodeTypeA' object attribute 'name' is read-only
如果未定义NodeTypeA.name
,则没有错误(旁注:该属性存在错误,并且没有理由在那里)。如果永远不会定义NodeTypeA.__slots__
,也没有错误,因此它有一个__dict__
。
我不明白的是:为什么超类中存在类变量会干扰在子类的槽中设置实例变量?
有人可以解释为什么这种组合会导致object attribute is read-only
错误吗?我知道我的例子是人为的,并且不太可能是真实程序中的故意,但这并不会使这种行为变得不那么奇怪。
谢谢,
乔纳森
答案 0 :(得分:17)
一个较小的例子:
class C(object):
__slots__ = ('x',)
x = 0
C().x = 1
通过为每个变量名创建描述符(实现描述符),在类级别实现
__slots__
。因此,类属性不能用于为__slots__
定义的实例变量设置默认值;否则,class属性将覆盖描述符赋值。
当使用__slots__
时,对插槽属性的属性分配需要通过为插槽属性创建的描述符。隐藏子类中的描述符会导致Python无法找到设置属性所需的例程。 Python仍然可以看到属性存在(因为它找到了遮蔽描述符的对象),因此它报告该属性是只读的。