Unexpected behavior of list of list
Steven D'Aprano
steve at REMOVE.THIS.cybersource.com.au
Fri Mar 9 21:58:59 EST 2007
On Fri, 09 Mar 2007 17:30:09 -0800, kghose wrote:
> Hi,
>
> The following code
>
> listoflists = [[]]*2
> listoflists[0].append(1)
>
> appends(1) to both listoflists[0] and listoflists[1] (which I did not
> expect)
I think you will find the same question raised barely a few hours ago.
Hint:
>>> list_of_lists = [[]]*2
>>> id(list_of_lists[0])
-1211466452
>>> id(list_of_lists[1])
-1211466452
Notice that both inner lists have the same ID? That tells you that they
are the same list.
Like about what [obj]*2 does. Does it create multiple copies of obj? No it
does not. Python never makes copies of objects unless you explicitly tell
it to.
[] on it's own creates a new empty list, so [[], []] creates a list with
two DIFFERENT empty lists in it. [[]] creates a list with one empty list
in it; *2 makes a second reference (not a copy!) of that empty list.
> while
>
> listoflists = [[]]*2
> listoflists[0] = [1]
> listoflists[0].append(2)
>
> works as expected.i.e. only listoflists[0] gets 2 appended to it and
> any further operations work as expected.
>>> list_of_lists[0] = [] # creates a new empty list
>>> id(list_of_lists[0])
-1211466228
>>> id(list_of_lists[1]) # same ID as before
-1211466452
You know, now that Python has a warnings module, it would be really good
if list-of-lists*int raised a warning. Does anyone know if that's feasible
or possible? It needn't catch every imaginable Gotcha, just the common
case. I'm thinking something like this:
# pseudo-code
class list:
def __mul__(self, count):
for item in self:
if isinstance(item, list):
warn("this duplicates references, not copies")
break
...do the rest
--
Steven.
More information about the Python-list
mailing list