17

我有一棵有数十万个节点的大树,我正在使用__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错误?我知道我的示例是人为的,在实际程序中不太可能是故意的,但这并没有使这种行为变得不那么奇怪。

谢谢,
乔纳森

4

1 回答 1

23

一个较小的例子:

class C(object):
    __slots__ = ('x',)
    x = 0

C().x = 1

关于插槽的文档在某一时刻指出:

__slots__通过为每个变量名创建描述符(实现描述符)在类级别实现。因此,类属性不能用于为定义的实例变量设置默认值__slots__;定义的实例变量的默认值。否则,类属性将覆盖描述符分配。

__slots__使用时,槽属性的属性分配需要通过为槽属性创建的描述符。隐藏子类中的描述符会导致 Python 无法找到设置属性所需的例程。但是,Python 仍然可以看到属性存在(因为它找到了隐藏描述符的对象),因此它报告该属性是只读的。

于 2011-04-22T17:16:10.040 回答