2011-04-22 62 views
14

我有一棵有成千上万个节点的大树,我使用__slots__来减少内存消耗。我只是发现了一个非常奇怪的错误并修复了它,但我不明白我看到的行为。Python,__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

'NodeTypeA'被创建类变量'name'和不将值分配给在'NodeBase'定义的实例变量。这是故意的吗? – unholysampler 2011-04-22 17:23:51

+0

起初并不是故意的 - 我在代码中意外地发现了这个问题,导致了我所问的错误。但后来我很好奇为什么代码的行为就像它一样,所以我故意将它放在我的代码示例中。 – Jonathan 2011-04-22 17:52:06

回答

17

较小例如:

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

C().x = 1 

在一个点上的documentation on slots状态:

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

我假设这意味着该实现会将具有在__slots__中使用的名称的类变量转换为只读描述符以防止此问题。

+1

类似的答案也张贴在这里:http://stackoverflow.com/questions/820671/python-slots-and-attribute-is-read-only – Santa 2011-04-22 17:25:57

+0

好点。我没有意识到它简化了 - 我认为继承是问题的一部分。显然,正如@圣诞老人指出的那样,这与之前的问题是一样的。 – Jonathan 2011-04-22 17:55:14

+0

Python不会在这里创建只读描述符。会发生什么是该实例没有'__dict__','NodeTypeA'中的'name =“Brian”'字符串隐藏了为'NodeBase'中的'name'插槽创建的插槽描述符。Python认为该实例具有'name'属性(因为属性查找找到了“Brian”字符串),但该属性不可分配(因为''Brian''没有'__set__'方法,而且实例没有'__dict__'),所以它报告属性是只读的。 – user2357112 2017-04-09 02:32:39

-1
class NodeBase(object): 
__slots__ = ["name"] 
def __init__(self, name): 
    self.name = name 

class NodeTypeA(NodeBase): 
    super().name = "Brian" 
    __slots__ = ["foo"] 

超级()

+1

Hi @ Tony-Diana,欢迎来到SO。请尽可能多地解释你的答案。 – 2017-04-09 08:54:32

+0

请为此代码添加解释并确认如何回答问题。 – 2017-04-09 17:39:09