strange side effect with lists!?

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Wed Oct 13 06:52:48 EDT 2004


Wolfgang.Stoecher at profactor.at wrote:
> Hello,
> 
> I'm new to Python and playing around. I'm confused by the following 
> behaviour:
> 
> 
>>>>l1 = [1] # define list
>>>>l2 = l1  # copy of l1 ?

No. Creation of another reference to l1.
you can test identity of objects with the 'is' operator :
 >>>> l2 is l1
True

>>>>l2,l1
> 
> ([1], [1])
> 
>>>>l2.extend(l1) # only l2 should be altered !?

No.

>>>>l2,l1
> 
> ([1, 1], [1, 1]) # but also l1 is altered!

Exactly what one would expect !-)

> So what is the policy of assignment? When is a copy of an object created? 

(please someone correct me if I say any stupidity)

There are two point you need to understand : bindings, and 
mutable/immutable types.

With Python, you've got objects, symbols and binding. Unlike languages 
like C, a 'variable' (we'd better say 'symbol' or 'name', and you may 
also read 'binding') is not the memory address of an object, but a 
reference to an object.

The syntax :
 >>>> l1 = [1]
creates a list object, and 'bind' the symbol (or 'name' if you prefer) 
'l1' to that list object - which means that l1 holds a reference to the 
list object. Now when you're doing
 >>>> l2 = l1
you're binding the symbol l2 to whatever l1 is bound to at this time.

Now there are two kind of objects : mutables and immutables. As 
expected,  you can modify mutable objects after instanciation, and you 
can not modify immutable objects. But you can modify the binding between 
a symbol and an immutable object, so when you're doing something like :
 >>> a = "aaa"
and then
 >>> a = a + "bbb"
this do *not* modify the string - what it does is create a new string 
made of "aaa" and "bbb" and rebind the symbol 'a' to the newly created 
string.

Most Python objects are mutables. Immutable objects are mainly numerics, 
strings and tuples.

So what happens with instanciation, modification, bindings, references etc ?

As I said, when you're binding two symbols to the same object (as you 
did in your exemple), both symbols reference the same object. Now what 
happens when you modify the bound object depends on the "mutability 
status" (pardon my poor english) of this object.

Let's have an exemple with an immutable object :

01]>>> a = "aaa"
02]>>> b = a
03]>>> a
04]'aaa'
05]>>> b
06]'aaa'
07]>>> a is b
08]True
09]>>> b = b + "bbb"
10]>>> a
11]'aaa'
12]>>> b
13]'aaabbb'
14]>>> a is b
15]False
16]>>>

Ok, this works as expected : a string being immutable, the statement at 
line 09 creates a new string and bind b to this string (or this string 
to b if you prefer...). So we now have two distinct string objects

Now with a mutable object :

 >>> a = [1]
 >>> b = a
 >>> a is b
True
 >>>

Ok, now we have to symbols referencing the same mutable object. Since 
this is a *mutable* object, modifying it will not create a new object. 
So none of the symbols will be rebound :

 >>> a.append(2)
 >>> a
[1, 2]
 >>> b
[1, 2]
 >>> a is b
True
 >>>

Once again, this works *exactly* as expected - once you understand the 
difference between binding and assignement, and the difference between 
mutable and immutable objects.

A common pitfall is :
 >>> a = b = []
This does not create two lists. This create one list and bind both 'a' 
and 'b' to this list.

Now back to your problem. You want a copy of the list, not another 
reference to the same list. Here the solution is
 >>> a = [1]
 >>> b = a[:]
 >>> a is b
False
 >>> a.append(2)
 >>> a
[1, 2]
 >>> b
[1]
 >>>


> Where to find dox on this?

In the fine manual ?-)
Ok, that's not really obvious from the tutorial. You may want to have a 
look here :
http://www.python.org/doc/current/ref/types.html

HTH
Bruno




More information about the Python-list mailing list