new_list = my_list doesn't actually create a second list. The assignment just copies the reference to the list, not the actual list, so both new_list and my_list refer to the same list after the assignment.
To actually copy the list, you have several options:
You can use the built-in
list.copy()method (available since Python 3.3):new_list = old_list.copy()You can slice it:
new_list = old_list[:]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).
You can use the built-in
list()constructor:new_list = list(old_list)You can use generic
copy.copy():import copy new_list = copy.copy(old_list)This is a little slower than
list()because it has to find out the datatype ofold_listfirst.If you need to copy the elements of the list as well, use generic
copy.deepcopy():import copy new_list = copy.deepcopy(old_list)Obviously the slowest and most memory-needing method, but sometimes unavoidable. This operates recursively; it will handle any number of levels of nested lists (or other containers).
Example:
import copy
class Foo(object):
def __init__(self, val):
self.val = val
def __repr__(self):
return f'Foo({self.val!r})'
foo = Foo(1)
a = ['foo', foo]
b = a.copy()
c = a[:]
d = list(a)
e = copy.copy(a)
f = copy.deepcopy(a)
# edit orignal list and instance
a.append('baz')
foo.val = 5
print(f'original: {a}\nlist.copy(): {b}\nslice: {c}\nlist(): {d}\ncopy: {e}\ndeepcopy: {f}')
Result:
original: ['foo', Foo(5), 'baz']
list.copy(): ['foo', Foo(5)]
slice: ['foo', Foo(5)]
list(): ['foo', Foo(5)]
copy: ['foo', Foo(5)]
deepcopy: ['foo', Foo(1)]
Answer from Felix Kling on Stack OverflowE0_copy is not a deep copy. You don't make a deep copy using list(). (Both list(...) and testList[:] are shallow copies, as well as testList.copy().)
You use copy.deepcopy(...) for deep copying a list.
copy.deepcopy(x[, memo])Return a deep copy of x.
See the following snippet -
>>> a = [[1, 2, 3], [4, 5, 6]]
>>> b = list(a)
>>> a
[[1, 2, 3], [4, 5, 6]]
>>> b
[[1, 2, 3], [4, 5, 6]]
>>> a[0][1] = 10
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b # b changes too -> Not a deepcopy.
[[1, 10, 3], [4, 5, 6]]
Now see the deepcopy operation
>>> import copy
>>> b = copy.deepcopy(a)
>>> a
[[1, 10, 3], [4, 5, 6]]
>>> b
[[1, 10, 3], [4, 5, 6]]
>>> a[0][1] = 9
>>> a
[[1, 9, 3], [4, 5, 6]]
>>> b # b doesn't change -> Deep Copy
[[1, 10, 3], [4, 5, 6]]
To explain, list(...) does not recursively make copies of the inner objects. It only makes a copy of the outermost list, while still referencing the same inner lists, hence, when you mutate the inner lists, the change is reflected in both the original list and the shallow copy. You can see that shallow copying references the inner lists by checking that id(a[0]) == id(b[0]) where b = list(a).
In Python, there is a module called copy with two useful functions:
import copy
copy.copy()
copy.deepcopy()
copy() is a shallow copy function. If the given argument is a compound data structure, for instance a list, then Python will create another object of the same type (in this case, a new list) but for everything inside the old list, only their reference is copied. Think of it like:
newList = [elem for elem in oldlist]
Intuitively, we could assume that deepcopy() would follow the same paradigm, and the only difference is that for each elem we will recursively call deepcopy, (just like mbguy's answer)
but this is wrong!
deepcopy() actually preserves the graphical structure of the original compound data:
a = [1,2]
b = [a,a] # there's only 1 object a
c = deepcopy(b)
# check the result
c[0] is a # False, a new object a_1 is created
c[0] is c[1] # True, c is [a_1, a_1] not [a_1, a_2]
This is the tricky part: during the process of deepcopy(), a hashtable (dictionary in Python) is used to map each old object ref onto each new object ref, which prevents unnecessary duplicates and thus preserves the structure of the copied compound data.
Official docs
Hi there! beginner Python programmer here~
I've been thinking more and more about what Python is doing in the background because I've noticed that it improves the way I think of writing programs. And because I had to copy a list in one of my school assignments, I got curious about what the best way to go about it is.
I looked it up and got a bunch of articles explaining about copy() and deepcopy() in detail, explaining how deepcopy is used when dealing with lists with mutable elements, etc. So, I guess I understand what those two are doing to an extent.
However, when it comes to copying a list with slicing (cloning) or by using list(), all I've been able to find is that cloning is much faster because it just copies a piece of memory onto a new location, and with list() the function needs to be called first. That I understand. But when would I want to use the one method over the other? Or when would I rather use list() instead of copy()?? does list() copy shallow or deep??? would I only want to use cloning when my goal is speed? does one use up more memory than the other? Those are questions that pop into my head.
And it doesn't stop there because I found this one article ( Python | Cloning or Copying a list - GeeksforGeeks ) that explains FIVE other ways to copy a list... Does Python just have multiple ways to copy a list in the same way??? or is it because Python language updates that caused there to be overlap?? Or does every technique have a specific purpose/result, even if the difference might be slight??
I have also found a few articles that might have discussed this in greater detail, but they were just too complicated for me to understand. I have only been doing this for a few weeks