7

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]
6
  • 2
    Yeah, that's what = does. :-) Commented Sep 1, 2010 at 14:57
  • 1
    there are no variables in python, only names and objects. Commented Sep 1, 2010 at 15:19
  • @hop: But aren't the names reference variables? Commented Sep 1, 2010 at 15:22
  • 2
    @recursive: It depends on how you define "variables", but it's usually easier to think about if you don't consider Python names to be the same thing as variables. See: python.net/crew/mwh/hacks/objectthink.html Commented Sep 1, 2010 at 15:45
  • 1
    So why would you ever want two names for the same object? Commented Dec 14, 2012 at 12:38

5 Answers 5

13

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[:].

Sign up to request clarification or add additional context in comments.

Comments

7

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.

Comments

3

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.

Comments

3

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

1 Comment

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.
0

In addition to the aforementioned comments, some additional steps must be taken in case of multi dimensional arrays. For instance, when you have a two dimensional array a = [[0,1,2],[3,4],[5,6,7,8]], the code b = a will not create an independent copy. However, it will create another reference to the references of the same one dimensional lists within the two dimensional list. To solve this, you must use one of the aforementioned methods for every list within the two dimensional list. For example, b = [i[:] for i in a] will create an independent copy of the list.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.