2016-12-13 112 views
0

我對下面的Python行爲感到莫名其妙。爲什麼第二個和第三個實例(b,c,i)的屬性是類屬性ia的行爲有所不同?爲什麼更改實例變量也會改變靜態變量?

In [47]: class Foo: 
    ...:  i=0 
    ...: 

In [48]: a = Foo() 

In [49]: a.i = 1 

In [50]: a.i 
Out[50]: 1 

In [51]: Foo.i 
Out[51]: 0 

In [52]: b = Foo() 

In [53]: b.i 
Out[53]: 0 

In [54]: Foo.i is b.i 
Out[54]: True 

In [55]: Foo.i is a.i 
Out[55]: False 

In [56]: c = Foo() 

In [57]: Foo.i is c.i 
Out[57]: True 
+1

慎用解釋的'int值int'的結果... Python的緩存小整數。雖然在這種情況下,我認爲這不會影響你的演示,但也許最好使用一個虛擬類來進行演示。 –

回答

6

這是發生了什麼事。當你這樣做:

a.i = 1 

你使用一個名稱創建一個實例變量,陰影類屬性。 class屬性仍然存在,但:

>>> class Foo: 
...  i = 0 
...  
>>> a = Foo() 
>>> Foo.i 
0 
>>> a.i = 69 
>>> a.i 
69 
>>> a.__class__.i 
0 
>>> del a.i # deletes the instance attribute, resolving lookup on class 
>>> a.i 
0 

要了解住在實例的命名空間中,檢查出的實例字典:

>>> a = Foo() 
>>> a.__dict__ 
{} 
>>> a.i = 1 
>>> a.__dict__ 
{'i': 1} 
0

a.i = 1不會改變Foo.i你打算。它相當於分配了一個實例成員a。如果您看到a.__dict__b.__dict__,則非常清楚。

In [11]: a.__dict__ 
Out[11]: {'i': 1} 

In [13]: b.__dict__ 
Out[13]: {} 

如果你想真的改變類成員變量,你應該使用Foo.i = 1。這將影響所有Foo實例。同樣,它在Foo.__dict__上非常清楚。

In [17]: Foo.__dict__ 
Out[17]: 
mappingproxy({'__dict__': <attribute '__dict__' of 'Foo' objects>, 
       '__doc__': None, 
       '__module__': '__main__', 
       '__weakref__': <attribute '__weakref__' of 'Foo' objects>, 
       'i': 0})