2013-03-07 50 views
1

我有以下代碼:如何使用修飾器修改可變類變量?

class X(object): 
    items = [] 

class Y(X): 
    pass 

class Z(X): 
    pass 

我試圖創建一個裝飾,將一個對象只添加爲Y的「項目」列表中。所以下面的代碼,

@addItems 
class Y(X): 
    pass 

應該附加的東西(例如起見,假設整數1)Y.items但不能修改X.items,Z.items,或X的任何其他子類基本上,Y.items應該有items = [1],但X.items和Z.items應該都有items = []。這是我創建了應該爲實現這一目標的裝飾功能定義:

def addItems(cls): 
    cls.items.append(1) 
    return cls 

這不工作,雖然 - 當我使用的裝飾,它結束了修改X的「項目」列表和其他所有子類的X.什麼給?我知道Python中的類屬性在X的所有實例之間共享,但是,我不知道子類受到了影響。也許這種行爲只發生在可變屬性上?

什麼是實現我的目標的正確方法?

+0

由於Y沒有'items'屬性,它會搜索超類並找到X.你想達到什麼目標? – Keith 2013-03-07 06:13:12

回答

2

這個問題不是裝飾者。您對「items」屬性的存儲位置/方式存在誤解。 YZ沒有自己的items屬性。相反,只有一個items屬性。你在X上定義了它,如果你的確做了Y.items(或Z.items),由於該子類沒有找到該屬性,所以它在超類上被動態查找。如果你這樣做X.items is Y.items你會看到它評價爲True ---只有一個items列表。這意味着當你修改它時,所有的類都會看到修改。

如果你想給每個類自己的items列表中,你必須這樣做,好,給每個班級自己的items名單:

class X(object): 
    items = [] 

class Y(object): 
    items = [] 

class Z(object): 
    items = [] 

的Python從來沒有拷貝任何東西,除非你告訴它。僅僅因爲你定義了一個從具有屬性的類繼承的子類,這並不意味着Python爲子類創建了一個新的屬性副本;它只是重新使用超類中的同一個對象。

如果你想「神奇」給每個類自己的項目屬性,你可以做到這一點的裝飾裏面:

def addItems(cls): 
    cls.items = [] 
    cls.items.append(1) 
    return cls 

這第一臺類的items空列表。這實際上是在它所操作的特定類上設置屬性,而不是在任何子類或超類上。現在,當你訪問它時,它會按照你的預期工作。

+0

你的解釋很有道理。你的解決方案運行良好,但是有沒有什麼神奇的方式來達到這種效果,而不必爲每個子類重新指定屬性?原因是因爲在我的應用程序中,子類是由應用程序的用戶定義的,我試圖最小化他們需要編寫的樣板代碼的數量。 – trinth 2013-03-07 06:37:59

+0

@trinth:看到我編輯的答案。既然你已經在寫一個裝飾器,你可以讓你的裝飾器在這個類上創建新的屬性。 – BrenBarn 2013-03-07 06:41:11

+0

我認爲這是如此優雅! – trinth 2013-03-07 06:47:02