2015-05-04 99 views
0

我只是expierenced一個奇怪的問題,我不明白:爲什麼兩個不同的對象包含相同的列表?

class A: 
    a_number = 666 

a = A() 
a2= A() 

a.a_number = 555 
print a2.a_number # => 666 

這種情況是完全清晰。但看看下面的例子:

class B: 
    a_list = [1,2] 

b = B() 
b2 = B() 

b.a_list[1] = 666 
print b2.a_list # => [1,666] 

爲什麼兩個不同的對象包含相同的列表?

+0

在第一個例子中,它們也包含相同的'a_number'。只是在第一個例子中,你給了其中一個新的'a_number',但在第二個例子中,你並沒有給出一個新的'a_list'。 – user2357112

+1

順便說一句,如果你在Python 2中,你的類應該從'object'繼承。閱讀:http://stackoverflow.com/questions/4015417/python-class-inherits-object –

回答

1

正如所有其他答案指出的那樣,a_list是一個類屬性,在所有實例之間共享。

a_number一個類屬性,在所有實例之間共享。那麼,爲什麼這是不同的?

正因爲如此:

a.a_number = 555 

即分配創建一個實例在實例a,隱藏類屬性屬性a_number。如果用列表做同樣的事情,你會得到同樣的效果:

>>> b.a_list = [1,2,3] 
>>> b2.a_list 
[1,2] 

但是,這不是你做了什麼。相反,你變異列表到位:

b.a_list[1] = 666 

這是一個分配給b.a_list[1],但它不是一個分配b.a_list。因此,它不會在b對象中創建實例屬性。

如果您可以就地變異a.a_number,它也會出現在a2.a_number。由於數字不可變,因此無法直接看到。但你可以通過比較a.a_number is a2.a_number或查看他們的id s間接看到它間接 s-雖然這不是一個完美的測試,因爲a.a_number, a2.a_number = 5, 5或甚至a.a_number, a2.a_number = 2+3, 6-1仍然可以給你相同的對象,而不是因爲它們仍然在使用類屬性,但是因爲它們現在都具有它們自己的實例屬性,兩者都引用相同的數字5對象。 *


*語言允許實現重用時,它知道價值是不可變的同一個對象。實際上,現有的主要實現方法是針對小整數,特殊的單例常量True,FalseNone,以及可能只有幾個字符串。使用(默認配置的)CPython,555666不被視爲小整數,但是5是。

+0

這是一個很好的分歧。謝謝! – 0xAffe

+0

@ 0xAffe:對b.a_list [1]進行賦值,而對b.a_list進行就地變換的這種想法一旦你想到它(或者至少你理解了__setitem__)就是有意義的。 ,但它與許多其他語言(以及就此而言,Python中的賦值和變量含義與C++不同)的整體概念是不同的,所以大多數人不會立即得到它...... – abarnert

+1

由於數字是不可變的,該語言可以重複使用預先存在的對象。這就是爲什麼'(1 + 2)是(4-1)'的原因,即使這些操作是獨立的。 –

0

它們不是兩個不同的對象。他們確實是單個對象B和B2對象指向同一個列表對象名單,如果您編輯B中相同的目錄列表是可變的,由B2引用

enter image description here

+0

這個答案的措辭是這樣的:它暗示'b'和'b2'是同一個對象。你應該改變這一點。 – user2357112

+0

但如果我打印b和b2,它會打印出兩個不同的內存地址。這是不是意味着他們是不同的對象? – 0xAffe

+0

b不是b2,但b.a_list是b2.a_list,這就是我的意思。所以改變b.a_list也會改變b2.a_list – c0d3

0

這是因爲a_list是類屬性,它對全部B實例是全局的。如果您希望B類的不同實例已是自己的名單,你應該在__init__這樣的定義:

class B: 
    def __init__(self): 
     self.a_list = [1,2] 
+1

是的,我已經發現我可以在構造函數中初始化它。但爲什麼a_list是類屬性,而a_number不是? – 0xAffe

+1

因爲您更改了列表,但是您替換了(實際上是隱藏的)數字。第一個不同之處在於賦值(它使a中的第二個a_number),第二個區別是整數是不可變的(因此不能像list.append那樣更改)。賦值後,a和A都包含屬性a_number,因此a不需要像a2那樣繼承它。 –

0

兩個對象甚至不包含列表,實際上。當你創建類B時,你會在其中放入a_list。當您訪問b.a_list時,口譯員發現b沒有a_list(您可以通過檢查b.__dict__來驗證此內容),並且可以更深入地看到該類。當看到b2時,完全相同的過程找到相同的列表。

MarcTudurí的答案顯示瞭如何在每個新的B實例中創建單獨的列表。

相關問題