2011-04-22 91 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