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 Overflownew_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)]
Felix already provided an excellent answer, but I thought I'd do a speed comparison of the various methods:
- 10.59 sec (105.9 µs/itn) -
copy.deepcopy(old_list) - 10.16 sec (101.6 µs/itn) - pure Python
Copy()method copying classes with deepcopy - 1.488 sec (14.88 µs/itn) - pure Python
Copy()method not copying classes (only dicts/lists/tuples) - 0.325 sec (3.25 µs/itn) -
for item in old_list: new_list.append(item) - 0.217 sec (2.17 µs/itn) -
[i for i in old_list](a list comprehension) - 0.186 sec (1.86 µs/itn) -
copy.copy(old_list) - 0.075 sec (0.75 µs/itn) -
list(old_list) - 0.053 sec (0.53 µs/itn) -
new_list = []; new_list.extend(old_list) - 0.039 sec (0.39 µs/itn) -
old_list[:](list slicing)
So the fastest is list slicing. But be aware that copy.copy(), list[:] and list(list), unlike copy.deepcopy() and the python version don't copy any lists, dictionaries and class instances in the list, so if the originals change, they will change in the copied list too and vice versa.
(Here's the script if anyone's interested or wants to raise any issues:)
from copy import deepcopy
class old_class:
def __init__(self):
self.blah = 'blah'
class new_class(object):
def __init__(self):
self.blah = 'blah'
dignore = {str: None, unicode: None, int: None, type(None): None}
def Copy(obj, use_deepcopy=True):
t = type(obj)
if t in (list, tuple):
if t == tuple:
# Convert to a list if a tuple to
# allow assigning to when copying
is_tuple = True
obj = list(obj)
else:
# Otherwise just do a quick slice copy
obj = obj[:]
is_tuple = False
# Copy each item recursively
for x in xrange(len(obj)):
if type(obj[x]) in dignore:
continue
obj[x] = Copy(obj[x], use_deepcopy)
if is_tuple:
# Convert back into a tuple again
obj = tuple(obj)
elif t == dict:
# Use the fast shallow dict copy() method and copy any
# values which aren't immutable (like lists, dicts etc)
obj = obj.copy()
for k in obj:
if type(obj[k]) in dignore:
continue
obj[k] = Copy(obj[k], use_deepcopy)
elif t in dignore:
# Numeric or string/unicode?
# It's immutable, so ignore it!
pass
elif use_deepcopy:
obj = deepcopy(obj)
return obj
if __name__ == '__main__':
import copy
from time import time
num_times = 100000
L = [None, 'blah', 1, 543.4532,
['foo'], ('bar',), {'blah': 'blah'},
old_class(), new_class()]
t = time()
for i in xrange(num_times):
Copy(L)
print 'Custom Copy:', time()-t
t = time()
for i in xrange(num_times):
Copy(L, use_deepcopy=False)
print 'Custom Copy Only Copying Lists/Tuples/Dicts (no classes):', time()-t
t = time()
for i in xrange(num_times):
copy.copy(L)
print 'copy.copy:', time()-t
t = time()
for i in xrange(num_times):
copy.deepcopy(L)
print 'copy.deepcopy:', time()-t
t = time()
for i in xrange(num_times):
L[:]
print 'list slicing [:]:', time()-t
t = time()
for i in xrange(num_times):
list(L)
print 'list(L):', time()-t
t = time()
for i in xrange(num_times):
[i for i in L]
print 'list expression(L):', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(L)
print 'list extend:', time()-t
t = time()
for i in xrange(num_times):
a = []
for y in L:
a.append(y)
print 'list append:', time()-t
t = time()
for i in xrange(num_times):
a = []
a.extend(i for i in L)
print 'generator expression extend:', time()-t
How to properly copy a list of dictionaries in python?
I just found out I've been copying lists wrong all along.
How may I copy a list of list without reference?
Why choose to copy a list with slices instead of copy(), deepcopy(), or list()??
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()
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
Hi, I'm a Python beginner and my preferred path is Data Science if this has anything to do with the question.
I've noticed in tutorials, that they sometimes copy a particular list that needs to be manipulated. Sometimes even when there's no obvious reason for that list to be copied, or when that original list won't be used again in the code.
Is this practice only with lists or with other types of variables as well? And why do we copy a list rather just manipulating the original one?