2012-09-01 66 views
5

我是Python新手。這裏有一個關於列表的問題: 據說列表是可變的,元組是不可變的。但是,當我寫:如何理解這個結果?

L1 = [1, 2, 3] 
L2 = (L1, L1) 
L1[1] = 5 
print L2 

結果是

([1, 5, 3], [1, 5, 3]) 

,而不是

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

L2是一個元組和元組是不可變的。爲什麼當我改變L1的值時,L2的值也改變了?

+0

看起來像你創建一個視圖,而不是一個深層複製? –

回答

4

該元組是不可變的,但元組內的列表是可變的。你改變了L1(列表),而不是元組。元組包含L1的兩個副本,所以它們都顯示更改,因爲它們實際上是同一個列表。

如果一個對象是「不可變的」,這並不意味着它觸及的所有東西都是不可變的。您可以將可變對象放入不可變對象內,並且這不會阻止您繼續對可變對象進行變異。

4

該元組沒有得到修改,它仍然包含相同的重複引用列表你給它。

你修改的列表L1),元組(或者更準確地說,不是參考到列表中的元組)。

比如你會不會能夠做到

L2[1] = 5 

因爲元組一成不變的,你正確的狀態。

所以元組沒有改變,但元組包含引用的列表被修改(因爲兩個條目都是對同一列表的引用,輸出中的兩個值都更改爲5)。元組中沒有值被改變。

如果您在此情況下將引用看作「指針」,可能會有所幫助。

編輯(在下面的評論基於問題的OP):

關於引用,列表和副本,也許這些例子會有所幫助:

L=range(5) 
s = (L, L[:]) # a reference to the original list and a copy 

s 
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4]) 

然後改變L [2]

L[2] = 'a' 

給出:

s 
([0, 1, 'a', 3, 4], [0, 1, 2, 3, 4]) # copy is not changed 

請注意,「2nd」列表沒有更改,因爲它包含副本。

現在,

L=range(5) 

我們正在創建的列表的兩個副本,並給予引用的元組

s = (L[:], L[:]) 

now 
L[2] = 'a' 

不會影響什麼,但原來的列表L

s 
([0, 1, 2, 3, 4], [0, 1, 2, 3, 4]) 

希望這有幫助。

+0

謝謝。這非常有幫助。當我在定義一個變量時提到一個列表時,是否有任何通用規則告訴我什麼時候該列表僅作爲一個引用被包含,並且列表是否作爲一個副本被包含?例如,如果我將變量A定義爲L1 [1],則L1作爲副本包含,但正如您所說的,當我將L2定義爲[L1,L1]時,將包含L1作爲參考。 – Rachaely

+0

@ user1641021如果使用切片符號(例如,L1 [:]),則您正在製作該列表的副本。我會在我的回答中多加一點,或許這會有所幫助。 – Levon

+0

@ user1641021我更新了我的答案,以解決您的一些問題,我希望它有幫助。 – Levon

1

元組包含兩個引用,每個引用都是相同的列表(不是列表的副本,正如您所預料的那樣)。因此,列表中的更改仍然會顯示在元組中(因爲元組只包含引用),但是元組本身沒有被更改。因此,不可侵犯性不受侵犯。

+0

如果我寫L1 = [1,2,3] A = L1 [1] L1 [1] = 5 打印A – Rachaely

+0

@ user1641021:在該片段中,首先製作一個列表並將其命名爲L1。然後,將名稱A綁定到L1 [1]所涉及的對象,該對象是整數2.然後將L1的第二個元素更改爲5,然後打印A,它仍然是2;你「指出」在整數2,而不是「L1的第二個元素」。 – DSM

+0

但是,如果我寫L1 = [1,2,3] A = L1 [1] L1 [1] = 5 打印A結果將是2而不是5.是否因爲'L1 [1]'包含L1的副本,而不是L1的參考,這樣即使L1改變了它的值,L1 [1]也不會? – Rachaely

7

從Python文檔(http://docs.python.org/reference/datamodel.html),請注意:

不可變容器對象,它包含了一個可變 對象的引用的值當後者的價值改變時可以改變;然而容器 仍然被認爲是不可變的,因爲它所包含的對象集合不能被 改變。因此,不變性與具有不變的價值並不完全相同,它更加微妙。

2

你說得對,元組是不可改變的:L2是兩個引用的不可變元組L1(不,因爲它可能會首先出現,兩個列表的元組),而L1並不是一成不變的。當你改變L1時,你不會改變L2,只是L2引用的對象。

2

使用deepcopy的代替=

從拷貝導入deepcopy的
L2 = deepcopy的(L1)

0

元組是不可變的手段只有一兩件事 - 一旦你構造一個元組,不可能修改它。另一方面,列表可以添加元素,從中刪除元素。但是,元組和列表都與它們包含的元素有關,但與這些元素的內容無關。

在Python中,這與元組或列表無關,當你添加一個簡單的值,比如一個int值時,它被表示爲is,但是像列表,元組或其他任何類的複雜值類型的對象是總是存儲爲參考。

如果你要你的元組轉換爲set(),你會得到那可能會讓你大吃一驚的錯誤消息,但鑑於上述,應該是有意義:

>>> L=range(5) 
>>> s = (L, L[:]) # a reference to the original list and a copy 
>>> set(1, 2, s) 
>>> set((1, 2, s)) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'list' 

由於值set絕決一旦它們被添加到集合中,則包含在不可變元組s內的任何可變值都將提升TypeError

+0

這使得看起來'int'不是'通過引用存儲'的方式與「複數值」相同,而是「表示爲」。但是'int'與'tuple'完全相同。 – DSM