Changing one list unexpectedly changes another, too
Question:
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?
Answers:
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?
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[:]
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)
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?“
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! 🙂
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?
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
andv
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?
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[:]
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)
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?“
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! 🙂