如何理解这个结果?

时间:2022-05-27 00:31:41

I am new to Python. Here is a question I have about lists: It is said that lists are mutable and tuples are immutable. But when I write the following:

我是Python的新手。这是我对列表的一个问题:据说列表是可变的,元组是不可变的。但是当我写下面的内容时:

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

the result is

结果是

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

instead of

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

But L2 is a tuple and tuples are immutable. Why is it that when I change the value of L1, the value of L2 is also changed?

但L2是一个元组,元组是不可变的。为什么当我改变L1的值时,L2的值也会改变?

7 个解决方案

#1


7  

From the Python documentation (http://docs.python.org/reference/datamodel.html), note:

从Python文档(http://docs.python.org/reference/datamodel.html),请注意:

The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.

包含对可变对象的引用的不可变容器对象的值可以在后者的值更改时更改;但是容器仍然被认为是不可变的,因为它包含的对象集合无法更改。因此,不变性与具有不可改变的价值并不完全相同,它更加微妙。

#2


4  

The tuple is immutable, but the list inside the tuple is mutable. You changed L1 (the list), not the tuple. The tuple contains two copies of L1, so they both show the change, since they are actually the same list.

元组是不可变的,但元组内的列表是可变的。你改变了L1(列表),而不是元组。元组包含两个L1副本,因此它们都显示更改,因为它们实际上是相同的列表。

If an object is "immutable", that doesn't automatically mean everything it touches is also immutable. You can put mutable objects inside immutable objects, and that won't stop you from continuing to mutate the mutable objects.

如果一个对象是“不可变的”,那么这并不意味着它触及的所有内容也是不可变的。您可以将可变对象放在不可变对象中,这不会阻止您继续改变可变对象。

#3


4  

The tuple didn't get modified, it still contains the same duplicate references to list you gave it.

元组没有被修改,它仍然包含与你给它的列表相同的重复引用。

You modified a list (L1), not the tuple (or more precisely, not the reference to the list in the tuple).

您修改了一个列表(L1),而不是元组(或更确切地说,不是对元组中列表的引用)。

For instance you would not have been able to do

例如,你无法做到

  L2[1] = 5

because tuples are immutable as you correctly state.

因为元组在你正确陈述时是不可变的。

So the tuple wasn't changed, but the list that the tuple contained a reference to was modified (since both entries were references to the same list, both values in the output changed to 5). No value in the tuple was changed.

因此元组没有改变,但是元组包含引用的列表被修改(因为两个条目都引用了相同的列表,输出中的两个值都变为5)。元组中的值没有改变。

It may help if you think of reference as a "pointer" in this context.

如果您将引用视为此上下文中的“指针”,则可能会有所帮助。

EDIT (based on question by OP in comments below):

编辑(根据OP在下面的评论中提出的问题):

About references, lists and copies, maybe these examples will be helpful:

关于参考,列表和副本,这些示例可能会有所帮助:

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])

then changing L[2]

然后改变L [2]

L[2] = 'a'

gives:

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

Notice that the "2nd" list didn't change, since it contains a copy.

请注意,“2nd”列表没有更改,因为它包含副本。

Now,

L=range(5)

we are creating two copies of the list and giving the references to the tuple

我们正在创建列表的两个副本并提供对元组的引用

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

now 
L[2] = 'a'

doesn't affect anything but the original list L

除了原始列表L之外不会影响任何其他内容

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

Hope this is helpful.

希望这有用。

#4


2  

You're right that tuples are immutable: L2 is an immutable tuple of two references to L1 (not, as it might first appear, a tuple of two lists), and L1 is not immutable. When you alter L1, you aren't altering L2, just the objects that L2 references.

你是对的,元组是不可变的:L2是两个对L1的引用的不可变元组(不是,因为它可能首先出现,是两个列表的元组),而L1不是不可变的。当您更改L1时,您不会更改L2,只会更改L2引用的对象。

#5


2  

Use deepcopy instead of = :

使用deepcopy而不是=:

from copy import deepcopy
L2 = deepcopy(L1)

来自copy import deepcopy L2 = deepcopy(L1)

#6


1  

The tuple contains two references, each to the same list (not copies of the list, as you might have expected). Hence, changes in the list will still show up in the tuple (since the tuple contains only the references), but the tuple itself is not altered. Therefore, it's immutability is not violated.

元组包含两个引用,每个引用都在同一个列表中(不是您可能预期的列表副本)。因此,列表中的更改仍将显示在元组中(因为元组仅包含引用),但元组本身不会更改。因此,它的不变性不会受到侵犯。

#7


0  

Tuples being immutable means only one thing -- once you construct a tuple, it's impossible to modify it. Lists, on the other hand, can be added elements to, removed elements from. But, both tuples and lists are concerned with the elements they contain, but not with what those elements are.

不可变的元组只意味着一件事 - 一旦你构造了一个元组,就不可能修改它。另一方面,列表可以添加元素,从中删除元素。但是,元组和列表都与它们包含的元素有关,但与这些元素的含义无关。

In Python, and this has nothing to do with tuples or lists, when you add a simple value, like an int, it gets represented as is, but any complex value like a list, a tuple, or any other class-type object is always stored as reference.

在Python中,这与元组或列表无关,当您添加一个简单的值(如int)时,它会按原样表示,但任何复杂的值(如列表,元组或任何其他类类型对象)都是始终存储为参考。

If you were to convert your tuple to a set(), you'd get an error message that might surprise you, but given the above it should make sense:

如果你要将你的元组转换为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'

As values of a set must never change once they are added to the set, any mutable value contained inside the immutable tuple s raises TypeError.

由于集合的值一旦被添加到集合中就不会改变,所以包含在不可变元组内的任何可变值都会引发TypeError。

#1


7  

From the Python documentation (http://docs.python.org/reference/datamodel.html), note:

从Python文档(http://docs.python.org/reference/datamodel.html),请注意:

The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.

包含对可变对象的引用的不可变容器对象的值可以在后者的值更改时更改;但是容器仍然被认为是不可变的,因为它包含的对象集合无法更改。因此,不变性与具有不可改变的价值并不完全相同,它更加微妙。

#2


4  

The tuple is immutable, but the list inside the tuple is mutable. You changed L1 (the list), not the tuple. The tuple contains two copies of L1, so they both show the change, since they are actually the same list.

元组是不可变的,但元组内的列表是可变的。你改变了L1(列表),而不是元组。元组包含两个L1副本,因此它们都显示更改,因为它们实际上是相同的列表。

If an object is "immutable", that doesn't automatically mean everything it touches is also immutable. You can put mutable objects inside immutable objects, and that won't stop you from continuing to mutate the mutable objects.

如果一个对象是“不可变的”,那么这并不意味着它触及的所有内容也是不可变的。您可以将可变对象放在不可变对象中,这不会阻止您继续改变可变对象。

#3


4  

The tuple didn't get modified, it still contains the same duplicate references to list you gave it.

元组没有被修改,它仍然包含与你给它的列表相同的重复引用。

You modified a list (L1), not the tuple (or more precisely, not the reference to the list in the tuple).

您修改了一个列表(L1),而不是元组(或更确切地说,不是对元组中列表的引用)。

For instance you would not have been able to do

例如,你无法做到

  L2[1] = 5

because tuples are immutable as you correctly state.

因为元组在你正确陈述时是不可变的。

So the tuple wasn't changed, but the list that the tuple contained a reference to was modified (since both entries were references to the same list, both values in the output changed to 5). No value in the tuple was changed.

因此元组没有改变,但是元组包含引用的列表被修改(因为两个条目都引用了相同的列表,输出中的两个值都变为5)。元组中的值没有改变。

It may help if you think of reference as a "pointer" in this context.

如果您将引用视为此上下文中的“指针”,则可能会有所帮助。

EDIT (based on question by OP in comments below):

编辑(根据OP在下面的评论中提出的问题):

About references, lists and copies, maybe these examples will be helpful:

关于参考,列表和副本,这些示例可能会有所帮助:

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])

then changing L[2]

然后改变L [2]

L[2] = 'a'

gives:

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

Notice that the "2nd" list didn't change, since it contains a copy.

请注意,“2nd”列表没有更改,因为它包含副本。

Now,

L=range(5)

we are creating two copies of the list and giving the references to the tuple

我们正在创建列表的两个副本并提供对元组的引用

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

now 
L[2] = 'a'

doesn't affect anything but the original list L

除了原始列表L之外不会影响任何其他内容

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

Hope this is helpful.

希望这有用。

#4


2  

You're right that tuples are immutable: L2 is an immutable tuple of two references to L1 (not, as it might first appear, a tuple of two lists), and L1 is not immutable. When you alter L1, you aren't altering L2, just the objects that L2 references.

你是对的,元组是不可变的:L2是两个对L1的引用的不可变元组(不是,因为它可能首先出现,是两个列表的元组),而L1不是不可变的。当您更改L1时,您不会更改L2,只会更改L2引用的对象。

#5


2  

Use deepcopy instead of = :

使用deepcopy而不是=:

from copy import deepcopy
L2 = deepcopy(L1)

来自copy import deepcopy L2 = deepcopy(L1)

#6


1  

The tuple contains two references, each to the same list (not copies of the list, as you might have expected). Hence, changes in the list will still show up in the tuple (since the tuple contains only the references), but the tuple itself is not altered. Therefore, it's immutability is not violated.

元组包含两个引用,每个引用都在同一个列表中(不是您可能预期的列表副本)。因此,列表中的更改仍将显示在元组中(因为元组仅包含引用),但元组本身不会更改。因此,它的不变性不会受到侵犯。

#7


0  

Tuples being immutable means only one thing -- once you construct a tuple, it's impossible to modify it. Lists, on the other hand, can be added elements to, removed elements from. But, both tuples and lists are concerned with the elements they contain, but not with what those elements are.

不可变的元组只意味着一件事 - 一旦你构造了一个元组,就不可能修改它。另一方面,列表可以添加元素,从中删除元素。但是,元组和列表都与它们包含的元素有关,但与这些元素的含义无关。

In Python, and this has nothing to do with tuples or lists, when you add a simple value, like an int, it gets represented as is, but any complex value like a list, a tuple, or any other class-type object is always stored as reference.

在Python中,这与元组或列表无关,当您添加一个简单的值(如int)时,它会按原样表示,但任何复杂的值(如列表,元组或任何其他类类型对象)都是始终存储为参考。

If you were to convert your tuple to a set(), you'd get an error message that might surprise you, but given the above it should make sense:

如果你要将你的元组转换为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'

As values of a set must never change once they are added to the set, any mutable value contained inside the immutable tuple s raises TypeError.

由于集合的值一旦被添加到集合中就不会改变,所以包含在不可变元组内的任何可变值都会引发TypeError。