I might be missing something about the intended behavior of list extend, but why does the following happen?
x = [[],[]]
y = [[]] * 2
print x # [[],[]]
print y # [[],[]]
print x == y # True
x[0].extend([1])
y[0].extend([1])
print x # [[1],[]], which is what I'd expect
print y # [[1],[1]], wtf?
I would guess that the *
operator is doing something unexpected here, though I'm not exactly sure what. It seems like something is going on under the hood that's making the original x and y (prior to calling extend) not actually be equal even though the ==
operator and repr
both would make it seem as though they were identical.
I only c开发者_运维百科ame across this because I wanted to pre-populate a list of empty lists of a size determined at runtime, and then realized that it wasn't working the way I imagined. I can find a better way to do the same thing, but now I'm curious as to why this didn't work. This is Python 2.5.2 BTW - I don't have a newer version installed so if this is a bug I'm not sure if it's already fixed.
In the case of [something] * 2
, python is simply making a reference-copy. Therefore, if the enclosed type(s) are mutable, changing them will be reflected anywhere the item is referenced.
In your example, y[0]
and y[1]
point to the same enclosed list object. You can verify this by doing y[0] is y[1]
or alternately id(y[0]) == id(y[1])
.
You can however re-assign list elements, so if you had done:
y[0] = [1]
You would've re-bound the first element to a new list containing the element "1", and you would've got your expected result.
Containers in python store references, and it's possible in most sequence containers to reference the same item multiple times. A list can actually reference itself as an element, though the usefulness of this is limited.
This issue wouldn't have come up if you had multiplied a list containing immutable types:
a = [0, 1] * 2
The above would give you the list [0, 1, 0, 1]
and indeed both instances of 1
point to the same object, but since they are immutable, you cannot change the value of the int
object containing "1", only reassign elements.
So doing: a[1] = 5
would result in a
showing as [0, 5, 0, 1]
.
The statement y = [[]] * 2
binds y
to a list containing 2 copies of the same list. Use:
y = [[], []]
or
y = [[] for n in range(2)]
y
contains two references to a single, mutable, list.
精彩评论