Changing one list unexpectedly changes another, too

Python points both lists in vec = v to the same spot of memory.

To copy a list use vec = v[:]


This might all seem counter-intuitive. Why not make copying the list the default behavior? Consider the situation

def foo():
    my_list = some_function()
    # Do stuff with my_list

Wouldn't you want my_list to contain the exact same list that was created in some_function and not have the computer spend extra time creating a copy. For large lists copying the data can take some time. Because of this reason, Python does not copy a list upon assignment.



Misc Notes:

  • If you're familiar with languages that use pointers. Internally, in the resulting assembly language, vec and v are just pointers that reference the address in memory where the list starts.

  • Other languages have been able to overcome the obstacles I mentioned through the use of copy on write which allows objects to share memory until they are modified. Unfortunately, Python never implemented this.

  • For other ways of copying a list, or to do a deep copy, see List changes unexpectedly after assignment. Why is this and how can I prevent it?


Run this code and you will understand why variable v changes.

a = [7, 3, 4]
b = a
c = a[:]
b[0] = 10
print 'a: ', a, id(a)
print 'b: ', b, id(b)
print 'c: ', c, id(c)

This code prints the following output on my interpreter:

a:  [10, 3, 4] 140619073542552                                                                                                
b:  [10, 3, 4] 140619073542552                                                                                                
c:  [7, 3, 4] 140619073604136

As you can see, lists a and b point to the same memory location. Whereas, list c is a different memory location altogether. You can say that variables a and b are alias for the same list. Thus, any change done to either variable a or b will be reflected in the other list as well, but not on list c Hope this helps! :)


Why does v change at all?

vec and v are both references.

When coding vec = v you assign v address to vec. Therefore changing data in v will also "change" vec.

If you want to have two different arrays use:

vec = list(v)

Because v is pointed to the same list as vec is in memory.

If you do not want to have that you have to make a

from copy import deepcopy
vec = deepcopy(v)

or

vec = v[:]