2016-06-27 65 views
3

我在學習thisthis以瞭解類屬性。但與以下代碼片段的輸出混淆。Python類中的類屬性shadowing

class A: 
    aliases = None 
    name = None 

    def __init__(self,name): 
     self.name = name 
     self.aliases = set([name]) 

    def add_aliases(self,a): 
     self.aliases.add(a) 

    def __repr__(self): 
     return str(self.name) + str(self.aliases) 

arr = [] 
for i in range(3): 
    arr.append(A(i)) 
    arr[-1].add_aliases(i+1) 

for item in arr: 
    print item 

A.aliases = set([]) ##Modify the static element of class 
for item in arr: 
    print item 

Python解釋器:2.7.9

和輸出是

0set([0, 1]) 
1set([1, 2]) 
2set([2, 3]) 
0set([0, 1]) 
1set([1, 2]) 
2set([2, 3]) 

而且我期待這樣的事情作爲輸出。

0set([2, 3]) 
1set([2, 3]) 
2set([2, 3]) 
0set([]) 
1set([]) 
2set([]) 
+0

這個問題不能重複,因爲這個問題試圖暗示'總是通過類名來引用類屬性,使你的代碼更易於理解。' – gjha

+0

你可能想看看我在原帖中給出的答案。 – Shasha99

回答

3

而且解釋是,當我們寫self.aliases = set([])我們其實創建一個實例屬性,陰影class屬性

所以,如果我們使我們的__init__函數如下,我們得到預期的輸出。

def __init__(self,name): 
    self.name = name 
    A.aliases = set([name]) #using the class attribute directly 

也可以考慮下面的代碼片段:

class A: 
    aliases = set([]) 
    name = None 

    def __init__(self,name): 
     self.name = name 
     self.aliases.add(name) # using the class attribute indirectly. 

    def add_aliases(self,a): 
     self.aliases.add(a) 

    def __repr__(self): 
     return str(self.name) + str(self.aliases) 

因爲在這種情況下,我們不創建實例屬性,沒有陰影。和問題的測試代碼,將產生這樣的輸出:

0set([0, 1, 2, 3]) 
1set([0, 1, 2, 3]) 
2set([0, 1, 2, 3]) 
0set([]) 
1set([]) 
2set([]) 

預計,作爲類屬性在所有實例共享。

這裏A.alias也可以被稱爲self.aliasinit或任何其他功能。而且由於它不影響靜態屬性,所以給出了預期的輸出結果 - 所有對象共享一個共同屬性的情況。在使用不可變的數據結構像string

一個人不知道這個概念不會注意到什麼,但在數據結構的情況下,像listdictionary這可能會帶來驚喜。

另請參考以下定義init

def __init__(self,name): 
    self.name = name 
    self.aliases.add(name) # referring to class attribute 
    self.aliases = set([]) # creating a instance attribute 

而這種情況下,也結束了創建instance attribute和測試代碼產生的輸出是:

0set([1]) 
1set([2]) 
2set([3]) 
0set([1]) 
1set([2]) 
2set([3]) 

,並形成這一切的我的學習是:

請務必參閱與類屬性類名稱和實例屬性與對象名稱,即寫A.aliases當您的意思是類屬性aliases,不要寫self.aliases間接參考self.aliases

+0

*「我們不會注意到我們是否使用不可變的數據結構」* - 真的嗎?我想大多數人會注意到,如果他們的其他班級沒有分享他們期望的屬性。 – jonrsharpe

+0

@jonrsharpe那麼鏈接的問題是這樣說的,我只是添加了這個問題來補充提到的兩個問題。 – gjha

+0

然後我想你已經誤解了其他問題關於可變與不可變類屬性的問題。這與他們分享狀態的更多關係是,當*不是*預期的時候,而不是在分享狀態時。 – jonrsharpe