Python, __slots__,继承与类变量 ==> 属性是只读错误
我有一棵很大的树,里面有成千上万个节点,我使用 __slots__ 来减少内存消耗。最近我发现了一个很奇怪的 bug,并且修复了它,但我不太明白我看到的行为。
这里有一段简化的代码示例:
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 的错误?我知道我的例子有点牵强,在真实程序中不太可能故意出现,但这并不妨碍这个行为看起来很奇怪。
谢谢,
Jonathan
相关问题:
1 个回答
26
这里有一个简单的例子:
class C(object):
__slots__ = ('x',)
x = 0
C().x = 1
关于 __slots__ 的文档中提到:
__slots__是在类的层面上通过为每个变量名创建描述符来实现的(实现描述符)。因此,类属性不能用来为由__slots__定义的实例变量设置默认值;否则,类属性会覆盖描述符的赋值。
当使用 __slots__ 时,给槽属性赋值需要通过为这些槽属性创建的描述符来进行。如果在子类中遮蔽了这些描述符,Python 就无法找到设置属性所需的例程。不过,Python 仍然能看到这个属性的存在(因为它找到了遮蔽描述符的对象),所以它会报告这个属性是只读的。