31

I have a list of the form

v = [0,0,0,0,0,0,0,0,0]

Somewhere in the code I do

vec=v
vec[5]=5

and this changes both v and vec:

>>> print vec
[0, 0, 0, 0, 0, 5, 0, 0, 0]
>>> print v
[0, 0, 0, 0, 0, 5, 0, 0, 0]

Why does v change at all?

ivan_pozdeev
  • 33,874
  • 19
  • 107
  • 152
sodiumnitrate
  • 2,899
  • 6
  • 30
  • 49
  • 1
    It is worth noting that this behaviour is is not limited to lists, it can also be observed with dict objects and would on tuple's too if they were mutable. – kpie Apr 21 '15 at 23:50
  • @SimeonVisser I couldn't have known in advance. If I had thought of searching with the keyword pointer, I would not have posted this question. – sodiumnitrate Apr 22 '15 at 00:14

5 Answers5

41

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)
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Erez Haim
  • 967
  • 8
  • 11
10

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[:]
stackattack
  • 354
  • 1
  • 11
5

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?

hostingutilities.com
  • 8,894
  • 3
  • 41
  • 51
5

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! :)

Dhananjay
  • 51
  • 1
  • 1
1

you could use

vec=v[:] #but

"Alex Martelli's opinion (at least back in 2007) about this is, that it is a weird syntax and it does not make sense to use it ever. ;) (In his opinion, the next one is more readable)."

vec=list(v)

I mean it was Erez's link... "How to clone or copy a list in Python?"

Community
  • 1
  • 1
kpie
  • 9,588
  • 5
  • 28
  • 50