Surprisingly, even advanced Python coders don’t know the details of the copy()
method of Python lists. Time to change that!
Definition and Usage: The list.copy()
method copies all list
elements into a new list. The new list is the return value of the method. It’s a shallow copy—you copy only the object references to the list elements and not the objects themselves.
Here’s a short example:
>>> lst = [1, 2, 3] >>> lst.copy() [1, 2, 3]
In the first line, you create the list lst
consisting of three integers. You then create a new list by copying all elements.
Syntax: You can call this method on each list object in Python. Here’s the syntax:
list.copy()
Arguments: The method doesn’t take any argument.
Return value: The method list.clear()
returns a list
object by copying references to all objects in the original list.
Video:
Related articles:
Here’s your free PDF cheat sheet showing you all Python list methods on one simple page. Click the image to download the high-resolution PDF file, print it, and post it to your office wall:
Python List Copy Shallow
Before you can truly understand the copy()
method in Python, you must understand the concept of a “shallow copy”.
In object-oriented languages such as Python, everything is an object. The list is an object and the elements in the list are objects, too. A shallow copy of the list creates a new list object—the copy—but it doesn’t create new list elements but simply copies the references to these objects.
You can see that the list below is only a shallow copy pointing to the same elements as the original list.
In Python, the list.copy()
method only produces a shallow copy which has much faster runtime complexity.
Here’s an example showing exact this scenario:
>>> lst = [6, 7, [1, 2], "hello"] >>> lst_2 = lst.copy() >>> lst_2[2].append(42) >>> lst[2] [1, 2, 42]
Changing the third list element of the copied list impacts the third list element of the original list.
Python List Copy Deep
Having understood the concept of a shallow copy, it’s now easy to understand the concept of a deep copy. A shallow copy only copies the references of the list elements. A deep copy copies the list elements themselves which can lead to a highly recursive behavior because the list elements may be lists themselves that need to be copied deeply and so on.
Here’s a simple deep copy of the same list as shown previously:
In contrast to the shallow copy, the list [1, 2]
is copied separately for the deep copy list. If one changes this nested list in the original list, the change would not be visible at the deep copy. (Because the nested list of the deep copy list is an independent object in memory.)
Note that in a deep copy, the string object must not be copied. Why? Because strings are immutable so you cannot change them (and, thus, there will be no dirty “side effects” seen by other copies of the list pointing to the same object in memory.
To get a deep copy in Python, use the copy module and use the deepcopy()
method:
>>> import copy >>> lst = [6, 7, [1, 2], "hello"] >>> lst_2 = copy.deepcopy(lst) >>> lst_2[2].append(42) >>> lst[2] [1, 2]
How to Copy a Python List (Alternatives)?
Say, you want to copy the list
. What options are there?
Method | Description |
---|---|
list.copy() | Returns a shallow copy of the list . |
import copy | Import the copy module and uses its method to create a deep copy of list . |
list[:] | Use slicing with default indices to create a shallow copy of the list . |
list(x) | use the built-in list constructor list(...) to create a shallow copy of the list x . |
[el for el in lst] | Use list comprehension to create a shallow copy of the original list lst . |
Slicing belongs to the fastest methods (very dirty benchmark here). If you need to refresh your Python slicing skills, here’s a tutorial on the Finxter blog:
Related Articles:
Python List Copy Not Working
The main reason why the list.copy()
method may not work for you is because you assume that it creates a deep copy when, in reality, it only creates a shallow copy of the list. To create a deep copy where the list elements themselves are copied (e.g. for multi-dimensional lists), simply import the copy
module and use its method deepcopy(x)
to copy list x
.
>>> import copy >>> lst = [[1, 2], 3, 4] >>> lst_2 = copy.deepcopy(lst)
Python List Copy And Append
How to copy a list and append an element in one line of Python code?
Simply use slicing to copy the list and the list concatenation operator +
to add the list of a single element [x]
to the result. But there are other nice ways, too. Check out the following ways to append element x
to a given list lst
and return the result as a copy:
- lst[:] + [x]
- lst.copy() + [x]
- [*lst, x]
The third way to copy a list and append a new element is my personal favorite because it’s fast, easy-to-read, and concise. It uses the asterisk operator to unpack the elements of the original list into a new list.
Python List Copy By Value
Do you want to copy all elements in your list “by value”? In other words, you want not only the list object to be copied (shallow copy) but also the list elements (deep copy).
This can be done with the deepcopy()
method of Python’s copy
library. Here’s an example:
>>> import copy >>> lst = [6, 7, [1, 2], "hello"] >>> lst_2 = copy.deepcopy(lst) >>> lst_2[2].append(42) >>> lst[2] [1, 2]
The element 42 was not appended to the nested list of lst
.
Python List Copy With Slice
You can simply copy a list lst
by using the slice operation lst[:]
with default start and stop indices so that all elements are copied in the list. This creates a shallow copy of the list lst
.
Related Articles:
Python List Copy Without First Element
To copy a list without its first element, simply use slicing list[1:]
. By setting the start index to 1 all elements with index larger or equal to 1 are copied into the new list.
Here’s an example:
>>> lst = [1, 2, 3, 4] >>> lst[1:] [2, 3, 4]
Python List Copy Without Last Element
To copy a list without its last element, simply use slicing list[:-1]
. By setting the start index to -1 (the right-most list element) all elements but the last one are copied into the new list.
Here’s an example:
>>> lst = [1, 2, 3, 4] >>> lst[:-1] [1, 2, 3]
Python List Copy Time Complexity
The time complexity of shallow list copying—examples are list.copy()
or slicing list[:]
—is linear to the number of elements in the list. For n list elements, the time complexity is O(n). Why? Because Python goes over all elements in the list and adds a copy of the object reference to the new list (copy by reference).
I wrote a quick script to evaluate that the time complexity of copying a list is, in fact, linear in the number of list elements:
import matplotlib.pyplot as plt import time y = [] for i in [100000 * j for j in range(10)]: lst = list(range(i)) t0 = time.time() lst_2 = lst[:] t1 = time.time() y.append(t1-t0) plt.plot(y) plt.xlabel("List elements (10**5)") plt.ylabel("Time (sec)") plt.show()
Here’s the result:
The runtime grows linearly in the number of list elements.
Python List Copy Partially
How to copy a list partially? To copy only the elements between start
index (included) and stop
index (excluded), use slicing like this: list[start:stop]
. This results in a new list that contains only parts of the list.
Python List Copy Multi-Dimensional List
To copy a multi-dimensional list (a list of lists), you need to create a deep copy. You can accomplish this with the copy library’s deepcopy() method as follows:
>>> import copy >>> lst = [[1, 2, 3], [4, 5, 6]] >>> lst_2 = copy.deepcopy(lst) >>> lst_2 [[1, 2, 3], [4, 5, 6]]
Now check if the copy is really deep by clearing the first list element in the copy:
>>> lst_2[0].clear() >>> lst [[1, 2, 3], [4, 5, 6]] >>> lst_2 [[], [4, 5, 6]]
You can see that the copy was really deep because the first element of the lst
was not affected by the clear() method that removed all elements for the deep copy lst_2
.
Python List copy() Thread Safe
Do you have a multiple threads that access your list at the same time? Then you need to be sure that the list operations (such as copy()
) are actually thread safe.
In other words: can you call the copy()
operation in two threads on the same list at the same time? (And can you be sure that the result is meaningful?)
The answer is yes (if you use the cPython implementation). The reason is Python’s global interpreter lock that ensures that a thread that’s currently working on it’s code will first finish its current basic Python operation as defined by the cPython implementation. Only if it terminates with this operation will the next thread be able to access the computational resource. This is ensured with a sophisticated locking scheme by the cPython implementation.
The only thing you need to know is that each basic operation in the cPython implementation is atomic. It’s executed wholly and at once before any other thread has the chance to run on the same virtual engine. Therefore, there are no race conditions. An example for such a race condition would be the following: the first thread reads a value from the list, the second threads overwrites the value, and the first thread overwrites the value again invalidating the second thread’s operation.
All cPython operations are thread-safe. But if you combine those operations into higher-level functions, those are not generally thread safe as they consist of many (possibly interleaving) operations.
Where to Go From Here?
The list.copy()
method creates a shallow copy of the list
. The copy.deepcopy(list)
method creates a deep copy of the list
.
You’ve learned the ins and outs of this important Python list method.
If you keep struggling with those basic Python commands and you feel stuck in your learning progress, I’ve got something for you: Python One-Liners (Amazon Link).
In the book, I’ll give you a thorough overview of critical computer science topics such as machine learning, regular expression, data science, NumPy, and Python basics—all in a single line of Python code!
OFFICIAL BOOK DESCRIPTION: Python One-Liners will show readers how to perform useful tasks with one line of Python code. Following a brief Python refresher, the book covers essential advanced topics like slicing, list comprehension, broadcasting, lambda functions, algorithms, regular expressions, neural networks, logistic regression and more. Each of the 50 book sections introduces a problem to solve, walks the reader through the skills necessary to solve that problem, then provides a concise one-liner Python solution with a detailed explanation.