2012-01-02 254 views
26

即時通訊有一個問題,瞭解類/實例變量如何在python中工作。我不明白爲什麼當我嘗試此代碼列表變量似乎是一個類變量python類實例變量和類變量

class testClass(): 
    list = [] 
    def __init__(self): 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

輸出:

['thing'] 
['thing', 'thing'] 

,當我做到這一點似乎是可變的一個實例

class testClass(): 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

p = testClass() 
print p.list 

f = testClass() 
print f.list 

輸出:

['thing'] 
['thing'] 

非常感謝

喬恩

+1

如果我理解正確,那麼您需要提供有關Python語法的特定設計決策背後的基本原理。對於這樣的問題,最好的答案是「因爲它符合語言的精神」,或者更明目張膽地說:「問問它的創造者」。 – Xion 2012-01-02 13:51:33

+0

好吧,所以變量是默認的類變量,這是我的困惑源於,這應該是我的問題,變量默認爲類變量 – 2012-01-02 13:55:42

+4

@jonathantopf不,變量默認情況下不是類變量。在Python中,你不聲明可變參數。對於這一點,它們實際上並不是變量(python是一個_variableless_ lanuage),只是名稱。而且你不要聲明或分配名字,你把它們綁定到一個對象上。運行時中的每個對象都有一個名稱到對象的字典。即使兩個對象屬於同一個類,它們也可以有非常不同的字典。 – rodrigo 2012-01-02 14:06:42

回答

40

這是因爲Python的方式解決與.名稱。當您編寫self.list時,Python運行時會嘗試先解析名稱爲list的名稱,然後在實例對象中查找它,如果在類實例中找不到該名稱。

讓我們來看看它一步

self.list.append(1) 
  1. 步驟是有一個list名稱到對象self
    • 是:使用它!完。
    • 否:轉至2.
  2. 是否有list名稱爲對象self的類的實例?
    • 是:使用它!完成
    • 否:錯誤!

但是當你綁定一個名字的東西是不同的:

self.list = [] 
  1. 是否有list名稱到對象self
    • 是:覆蓋它!
    • No:綁定它!

所以,這始終是一個實例變量。

您的第一個示例在類實例中創建list,因爲這是當時的活動範圍(任何地方都沒有self)。但是你的第二個例子在self的範圍內明確地創建了list

更有趣的將是例如:

class testClass(): 
    list = ['foo'] 
    def __init__(self): 
     self.list = [] 
     self.list.append('thing') 

x = testClass() 
print x.list 
print testClass.list 
del x.list 
print x.list 

,將打印:

['thing'] 
['foo'] 
['foo'] 

刪除實例名稱類名是通過self參考可見的那一刻。

+0

確定im以下,在那種情況下是否有方法來定義__init__函數以外的實例變量,我只是試圖在__init__之外執行'self.list []',這是有道理的,但有沒有辦法? – 2012-01-02 13:58:16

+0

@jonathantopf:實例變量只能在創建實例時創建。他們必須在一個實例化的方法中創建。你的其他選擇是重載'__new__'並在那裏創建它們,但這真的很醜陋,因爲它不是'__new__'真正的用處,它並不比在__init__中創建它們更好。什麼,祈禱 - 告訴,你認爲你需要這種能力?您可以創建一個元類來重載'__new__'來查看類的字典並將其複製到實例字典中。但是這真的很難看。 – Omnifarious 2012-01-02 14:01:02

+0

:)採取了一點,這是有道理的,我不喜歡問這樣的問題,但有時它是最好的方式來發現,如果我的想法是瘋了或不,現在我知道! – 2012-01-02 14:03:34

0

當你實例化一個類時,__init__方法被自動執行。

在第一種情況下,您的列表是一個類屬性並由其所有實例共享。你有兩件事是因爲你在即時p時附加了一個,而另一個在實例化f時(第一個在第一次調用時已經附加了第一個)。

3

在第一個示例中,list是該類的一個屬性,由其所有實例共享。這意味着,你甚至可以訪問它,而不必testClass類型的對象:

>>> class testClass(): 
...  list = [] 
...  def __init__(self): 
...    self.list.append("thing") 
... 
>>> testClass.list 
[] 
>>> testClass.list.append(1) 
>>> testClass.list 
[1] 

但是所有對象類,並分享彼此的list屬性:

>>> testObject = testClass() 
>>> testObject.list 
[1, 'thing'] 
>>> testClass.list 
[1, 'thing'] 
>>> 
>>> testObject2 = testClass() 
>>> testClass.list 
[1, 'thing', 'thing'] 
>>> testObject2.list 
[1, 'thing', 'thing'] 
4

Python有大約尋找有趣的規則名字。如果你真的想彎曲你的頭腦,試試這個代碼:

class testClass(): 
    l = [] 
    def __init__(self): 
     self.l = ['fred'] 

這會給每個實例名爲l變量,口罩類變量l。如果你做self.__class__.l,你仍然可以得到類變量。

我想到的方式是這樣的......每當你做instance.variable(即使是方法名稱,它們只是變量的值都是函數),它會在實例的字典中查找它。如果它在那裏找不到它,它會試圖在實例的類字典中查找它。這隻有在變量正在被讀取時纔有效。如果分配給它,它總是在實例字典中創建一個新條目。

+0

什麼迂迴併發症!這個答案真的很有用,因爲'閱讀與寫作'的案例讓我頭痛。 – dotslash 2016-01-17 05:28:57