Because python passes lists by reference
This means that when you write "b=a" you're saying that a and b are the same object, and that when you change b you change also a, and viceversa
A way to copy a list by value:
new_list = old_list[:]
If the list contains objects and you want to copy them as well, use generic copy.deepcopy():
import copy
new_list = copy.deepcopy(old_list)
Answer from Nikaido on Stack OverflowBecause python passes lists by reference
This means that when you write "b=a" you're saying that a and b are the same object, and that when you change b you change also a, and viceversa
A way to copy a list by value:
new_list = old_list[:]
If the list contains objects and you want to copy them as well, use generic copy.deepcopy():
import copy
new_list = copy.deepcopy(old_list)
Since Python passes list by reference, A and B are the same objects. When you modify B you are also modifying A. This behavior can be demonstrated in a simple example:
>>> A = [1, 2, 3]
>>> def change(l):
... b = l
... b.append(4)
...
>>> A
[1, 2, 3]
>>> change(A)
>>> A
[1, 2, 3, 4]
>>>
If you need a copy of A use slice notation:
B = A[:]
python list by value not by reference - Stack Overflow
How do I copy a list without replacing the original one?
python - Create a copy of the list not referencing the contained objects - Stack Overflow
I just found out I've been copying lists wrong all along.
You cannot pass anything by value in Python. If you want to make a copy of a, you can do so explicitly, as described in the official Python FAQ:
b = a[:]
To copy a list you can use list(a) or a[:]. In both cases a new object is created.
These two methods, however, have limitations with collections of mutable objects as inner objects keep their references intact:
>>> a = [[1,2],[3],[4]]
>>> b = a[:]
>>> c = list(a)
>>> c[0].append(9)
>>> a
[[1, 2, 9], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> b
[[1, 2, 9], [3], [4]]
>>>
If you want a full copy of your objects you need copy.deepcopy
>>> from copy import deepcopy
>>> a = [[1,2],[3],[4]]
>>> b = a[:]
>>> c = deepcopy(a)
>>> c[0].append(9)
>>> a
[[1, 2], [3], [4]]
>>> b
[[1, 2], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>>
Hey r/learnpython
I am having trouble copying a list from an imported script I made without changing the original list. I tried to use this code:
def spawn_npcs():
for npc in SETTINGS.levels_list[SETTINGS.current_level].npcs:
try:
stats = [x for x in SETTINGS.npc_types if x[0]['id'] == npc[2]][0].copy()
print(stats[0]['pos'], SETTINGS.npc_types[0][0]['pos'])
stats[0]['pos'] = npc[0]
except:
print("ERROR: No NPC with ID = ", npc[2])
print(stats[0]['pos'], SETTINGS.npc_types[0][0]['pos'])It prints [0,0] [0,0] to the console and then [4,4] [4,4]. It also changed the list in SETTINGS.py - How do I avoid that?
Thanks :-)
a[:] creates a shallow copy of the list.
You can use the copy.deepcopy() function to recursively copy the objects, or use a list comprehension:
b = [el[:] for el in a]
This creates a new list object with shallow copies of the nested list objects in a.
For that use deepcopy:
>>> from copy import deepcopy
>>> b = deepcopy(a)
>>> b[0][2] = 'change a'
>>> print a
[[1,2,3],[-1,-2,-3]]
Deepcopy: https://docs.python.org/2/library/copy.html#copy.deepcopy
Extension
Deepcopy also creates an individual copy of class instances. Please see simple example below.
from copy import deepcopy
class A:
def __init__(self):
self.val = 'A'
>>> a = A()
>>> b = deepcopy(a)
>>> b.val = 'B'
>>> print a.val
'A'
>>> print b.val
'B'
In order to explain this, assume we have two lists: some_numbers and other_numbers, where
>>> some_numbers = [1, 2, 3, 4, 5] >>> other_numbers = some_numbers
Many beginners would make a copy of some_numbers and store it in other_numbers, as I did above. However, what you might not know, is that when you do that you actually tell Python that they are the same list. So if you tried to add an item to some_numbers and then print(other_numbers), you'd see that the output will include the item you added to some_numbers. i.e.:
>>> some_numbers.append(10) >>> print(other_numbers) [1, 2, 3, 4, 5, 10]
If you wish to have two independent lists, where adding an item to one doesn't change the other, use this instead:
>>> some_numbers = [1, 2, 3, 4, 5] >>> other_numbers = some_numbers[:]
Now, you can change the lists independently.
>>> some_numbers.append(10) >>> other_numbers.append(20) >>> print(some_numbers) >>> print(other_numbers) [1, 2, 3, 4, 5, 10] [1, 2, 3, 4, 5, 20]
Edit: As mentioned in the comments by several people, the more readable option for copying is
>>> some_numbers = [ 1, 2, 3, 4, 5] >>> other_numbers = some_numbers.copy()