[英]How to make sense of this result?
我是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
的值也會改變?
從Python文檔(http://docs.python.org/reference/datamodel.html),請注意:
包含對可變對象的引用的不可變容器對象的值可以在后者的值更改時更改; 但是容器仍然被認為是不可變的,因為它包含的對象集合無法更改。 因此,不變性與具有不可改變的價值並不完全相同,它更加微妙。
元組是不可變的,但元組內的列表是可變的。 你改變了L1(列表),而不是元組。 元組包含兩個L1副本,因此它們都顯示更改,因為它們實際上是相同的列表。
如果一個對象是“不可變的”,那么這並不意味着它觸及的所有內容也是不可變的。 您可以將可變對象放在不可變對象中,這不會阻止您繼續改變可變對象。
元組沒有被修改,它仍然包含你給它的列表相同的重復引用。
您修改了一個列表 ( 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])
希望這是有幫助的。
你是對的,元組是不可變的:L2是兩個對L1的引用的不可變元組(不是,因為它可能首先出現,是兩個列表的元組),而L1不是不可變的。 當您更改L1時,您不會更改L2,只會更改L2引用的對象。
使用deepcopy而不是=
:
從復制導入deepcopy
L2 =深度掃描(L1)
元組包含兩個引用,每個引用都在同一個列表中(不是您可能預期的列表副本)。 因此,列表中的更改仍將顯示在元組中(因為元組僅包含引用),但元組本身不會更改。 因此,它的不變性不會受到侵犯。
不可變的元組只意味着一件事 - 一旦你構造了一個元組,就不可能修改它。 另一方面,列表可以添加元素,從中刪除元素。 但是,元組和列表都與它們包含的元素有關,但與這些元素的含義無關。
在Python中,這與元組或列表無關,當您添加一個簡單的值(如int)時,它會按原樣表示,但任何復雜的值(如列表,元組或任何其他類類型對象)都是始終存儲為參考。
如果你要將你的元組轉換為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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.