为什么python在修改时会将在同一行中声明的所有列表视为同一个对象?

时间:2017-07-06 09:28:17

标签: python list

在python3中假设我需要有3个空列表。我可以在3个单独的行中分别分配空列表。但是当我在同一行宣布它们时,如下所示

s1 , s2 , s3 = [[]]*3

每当我将一个元素附加到这些列表中的任何一个时,相同的元素就会附加到所有列表中。它与所有操作相同,每当我在一个列表中弹出一个项目时,所有三个列表s1,s2,s3都弹出一个项目。我无法理解这种行为

2 个答案:

答案 0 :(得分:3)

没有人真正回答OP,这是为什么 OP的原始语法(即s1 , s2 , s3 = [[]]*3)会将它们全部视为相同的列表(即更改其中一个列表将改变所有这些。)

为什么它们是相同的列表?

这是因为python列表只引用它们包含的内容,因此列表[[]]的列表只指向一个空列表。但是,当你将它乘以3时,它需要相同的空列表并引用它3次。

明智的例子

考虑这种情况会更直观。假设我们已经有了一个列表,我们想要重复该列表3次:

myList = ['me', 'myself', 'Irene']
three_myList = [myList] * 3
three_myList

然后你得到:

[['me', 'myself', 'Irene'],['me', 'myself', 'Irene'],['me', 'myself',
'Irene']]

但是,如果您更改列表中的值:

myList[2] = 'Tim'
three_myList

你得到:

[['me', 'myself', 'Tim'], ['me', 'myself', 'Tim'], ['me', 'myself', 'Tim']]

这是有道理的,因为three_myList仅引用myList 3次(使用指针)并更改myList。实际上,three_list要求myList的值为3次,因此所有3个引用都会一起更改。

结论

在您的情况下,您不希望s1s2s3引用相同的列表,但这样做是因为在作业的右侧,您构建了一个使用相同列表三次的列表。

简单列表不同

但是,它仍然令人困惑,因为一个非常相似的过程会导致不同的结果。假设你采用一个简单的列表(不是嵌套的)并将其加倍,那么它就不会更新:

triple_myList = myList * 3
triple_myList

给出:

['me', 'myself', 'Tim', 'me', 'myself', 'Tim', 'me', 'myself', 'Tim']

但是,当您更新时:

myList[2] = 'Irene'
triple_myList

长版没有:

['me', 'myself', 'Tim', 'me', 'myself', 'Tim', 'me', 'myself', 'Tim']

这是因为要将一个简单列表三倍化,我们必须将其内容一起粉碎三次以获得另一个简单(非嵌套)列表。评估这会强制进行新列表的计算。因此,triple_myList是一个新事物,实际上并不包含myList(作为元素),因此不会对myList进行任何引用。

其他评论

Nick Chapman的回答实际上只是将OP的结果集中在一行中的另一种语法,而不是解释为什么OP语法的工作原理。

Stan Zeez对OP的评论解释了如何获得不同的结果(3个单独的列表单独更新),但他使用了太多括号,因此它创建了3个双嵌套列表:

s1, s2, s3 = [[[]] for i in range(3)]
s1                     
# [[]]

这将创建3个像OP一样的简单列表(但这些列表实际上是独立的,与OP不同):

s1, s2, s3 = [[] for i in range(3)]

答案 1 :(得分:1)

好的,假设你的意思是:

s1 = s2 = s3 = [[]]

将其中一个附加到其他所有内容的原因是因为它们都指向同一个对象。 s2s3实际上只是s1的别名。如果您想要制作深层副本,请考虑查看copy模块:https://docs.python.org/3/library/copy.html