views:

141

answers:

4

What's going on with my Python variable? old_pos seems to be linked to pos:

Code:

pos = [7, 7]
direction = [1, 1]
old_pos = pos
print 'pos     = '+str(pos)
print 'old_pos = '+str(old_pos)
pos[0] += direction[0]
pos[1] += direction[1]
print 'pos     = '+str(pos)
print 'old_pos = '+str(old_pos)

Output:

pos     = [7, 7]
old_pos = [7, 7]
pos     = [8, 8]
old_pos = [8, 8]

However, if I replace old_pos = pos with old_pos = tuple(pos) or even old_pos = list(pos), I don't get this problem:

pos     = [7, 7]
old_pos = [7, 7]
pos     = [8, 8]
old_pos = [7, 7]
+10  A: 

When you say old_pos = pos, you are not creating a copy of pos, but just making another reference to the same list. If you want two lists that behave independently, you'll need to make a copy, like using the list(pos) function as you mention, or using the slice notation pos[:].

recursive
+3  A: 

old_pos seems to be linked to pos

Correct - this:

old_pos = pos

makes old_pos and pos point to the same list. It doesn't create a new copy of pos.

Richard Fearn
+3  A: 

recursive is right about the cause. You can see that they have identical memory addresses:

>>> pos = [7, 7]
>>> old_pos = pos
>>> id(pos)
4299304472
>>> id(old_pos)
4299304472

This is called passing by reference, versus passing by value. You can also remedy this situation by using the copy module.

>>> from copy import copy
>>> pos = [7, 7]
>>> old_pos = pos
>>> id(pos)
4299304472
>>> id(old_pos)
4299304472
>>> old_pos = copy(pos)
>>> id(old_pos)
4299349240
cpharmston
Um... it's not really *passing by reference* because you're not **passing** anything in the example. It's just that Python names have *reference semantics* in how they refer to Python objects.
Daniel Pryden
+4  A: 

old_pos = pos does not create a copy of the object refered to by the name pos, rather it creates a second reference called old_pos to the very same object. Actions done to pos affect the same object referred to by old_pos. In the same way, the names "Steven" and "Mr. Rumbalski" both refer to me. If you punch Steven in the face, Mr. Rumbalski will be injured, because the two names refer to the same object -- me.

Here are 3 ways to make an actual copy instead of a second reference:

Using slice notation

old_pos = pos[:]

Using the list constructor

old_pos = list(pos)

Using the copy module

from copy import copy
old_pos = copy(pos)

Note that these copies are all shallow copies, which in this case is fine. To learn about the difference between shallow copy and deep copy read the documentation of the copy module.

Steven Rumbalski
+1 excellent metaphor.
Daniel Pryden