简体   繁体   English

Python:为什么追加到列表会产生相同的值

[英]Python: why appending to a list results in same values

This is my code: 这是我的代码:

a = []
res = []
for i in range(0, 3):
    a.append(i)
    res.append(a)
print(res)

The result is: 结果是:

[[0, 1, 2], [0, 1, 2], [0, 1, 2]] 

But I want the result to be: 但我希望结果是:

[[0], [0, 1], [0, 1, 2]]

I know the solution is using the shallow copy: res.append(a[:]) . 我知道解决方案正在使用浅表副本: res.append(a[:]) But can somebody tell me why? 但是有人可以告诉我为什么吗?

You appended the same thing ( a ) to res three times, so it appears 3 times. 您将同一事物( a )追加到res了三遍,因此它出现了3次。 The fact that you changed the contents of a between each call to append doesn't matter. 你改变的内容,这一事实a每个电话之间的append无所谓。 If each call to append was given its own copy of a , then you'd get the result you expect. 如果每次调用append给予其自身的拷贝 a ,然后你会得到你所期望的结果。

when you append the object "a", python actually appends a pointer that points to the original list "a". 当您附加对象“ a”时,python实际上会附加一个指向原始列表“ a”的指针。 In the next iteration of the loop you change the original object, so all of the pointers to that object show the latest state of the object. 在循环的下一个迭代中,您将更改原始对象,因此指向该对象的所有指针都将显示该对象的最新状态。 you can add print the lists in every iteration to see that in action. 您可以在每次迭代中添加打印列表,以查看实际效果。 What you want is to create a copy of "a", that would remain unchanged, and append the copy to "res". 您想要的是创建一个副本“ a”,该副本将保持不变,并将该副本附加到“ res”中。 Like you said, using the syntax a[:] would do the job. 就像您说的那样,使用语法a [:]可以完成这项工作。

When you append a to the res array, you are appending a pointer to the a variable. 当将a附加到res数组时,就是将指针附加到a变量。 Not the 'value' of the a variable. 不是a变量的“值”。 So when you are done, the res array has the 'value' - [a, a, a]. 因此,完成后, res数组将具有“值”-[a,a,a]。

When you shallow copy, you are copying the 'value' of the a variable at that stage of the loop into the res array, giving you a 'value' of - [[0],[0,1],[0,1,2]]. 浅表复制时,将在循环的那个阶段变量的“值”复制到res数组中,从而为您提供-[[0],[0,1],[0,1]的“值” ,2]]。

a = []                    # (1) list created here
res = []
for i in range(0, 3):
    a.append(i)           # (2) list modified here
    res.append(a)         # (3) res is modified here
print(res)

What your code is saying is this: 您的代码在说什么:

At (1) a list is created and a refers to this list . 在(1)创建一个lista引用该list

At (2) you modify the list from (1), but the list itself remains at the same memory location and a still refers to this list. 在(2)修改list从(1),但列表本身保持在相同的内存位置和a仍然指向这个列表。

At (3) you just make a copy of a reference and add it to res , and still neither a nor the list at (1) change. 在(3)处,您只需复制一个引用并将其添加到res ,仍然( a或(1)处的列表都不变。

The end results is that res gets 3 copies of the reference to the list at (1). 最终结果是res在(1)处获得对该列表的引用的3个副本。

Here is a side effect: 这是一个副作用:

a[1] = 42
print(res)

Output: 输出:

[[0, 42, 2], [0, 42, 2], [0, 42, 2]]

You say that you know that this is the code you are after: 您说您知道这是您要执行的代码:

a = []
res = []
for i in range(0, 3):
    a.append(i)
    res.append(a[:])     # (4) new list created
print(res)

At (4) a new list is created whose contents is the same as the list that a refers to. 在(4),创建一个新列表,其内容与a引用的列表相同。 This new list is not referred to by a , but instead, one of the elements of res has a reference to this new list. 这个新的列表不会被称为a ,而是的要素之一res有这个新的列表的引用。

Firstly this means that res holds references to lists, which is why they hang around long enough to be printed. 首先,这意味着res保留对列表的引用,这就是为什么它们要挂足够长的时间才能被打印。 Secondly a still refers to the original list. 其次a仍然引用原始列表。

Here is a side effect: 这是一个副作用:

a[1] = 42
print(res)

Output: 输出:

[0, 42, 2] [[0], [0, 1], [0, 1, 2]]

However, this is not the end of the story if you examine this code: 但是,如果您检查以下代码,这还不是故事的结尾:

a = []
res = []
for i in range(0, 3):
    a.append([i])        # (5) Create a new list with one element
    res.append(a[:])     # (6) Shallow copy as above
print(res)

a[1].append(42)
print(a, res)

Output: 输出:

[[[0]], [[0], [1]], [[0], [1], [2]]]
[[0], [1, 42], [2]] [[[0]], [[0], [1, 42]], [[0], [1, 42], [2]]]

This occurs because at (6) there was only a shallow copy made. 发生这种情况是因为在(6)处仅进行了浅拷贝。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM