Why does foo.append(bar) affect all elements in a list of lists?
I create a list of lists and want to append items to the individual lists, but when I try to append to one of the lists (a[0].append(2)
), the item gets added to all lists.
a = []
b = [1]
a.append(b)
a.append(b)
a[0].append(2)
a[1].append(3)
print(a)
Gives: [[1, 2, 3], [1, 2, 3]]
Whereas I would expect: [[1, 2], [1, 3]]
Changing the way I construct the initial list of lists, making b
a float instead of a list and putting the brackets inside .append()
, gives me the desired output:
a = []
b = 1
a.append([b])
a.append([b])
a[0].append(2)
a[1].append(3)
print(a)
Gives: [[1, 2], [1, 3]]
But why? It is not intuitive that the result should be different. I know this has to do with there being multiple references to the same list开发者_如何学JAVA, but I don't see where that is happening.
It is because the list contains references to objects. Your list doesn't contain [[1 2 3] [1 2 3]]
, it is [<reference to b> <reference to b>]
.
When you change the object (by appending something to b
), you are changing the object itself, not the list that contains the object.
To get the effect you desire, your list a
must contain copies of b
rather than references to b
. To copy a list you can use the range [:]
. For example:
>>> a = []
>>> b = [1]
>>> a.append(b[:])
>>> a.append(b[:])
>>> a[0].append(2)
>>> a[1].append(3)
>>> print a
[[1, 2], [1, 3]]
The key is this part:
a.append(b)
a.append(b)
You are appending the same list twice, so both a[0]
and a[1]
are references to the same list.
In your second example, you are creating new lists each time you call append like a.append([b])
, so they are separate objects that are initialized with the same float value.
In order to make a shallow copy of a list, the idiom is
a.append(b[:])
which when doubled will cause a to have two novel copies of the list b
which will not give you the aliasing bug you report.
精彩评论