Why is it when you copy a list in Python doing
b_list = a_list
that, any changes made to
modify the other list?
If you’ve played with lists in Python you will reach a point where you want to copy a list to make modifications to it without changing the original list. Initially you would think the following would work:
>>> a_list = [1, 2, 3] >>> b_list = a_list >>> b_list.append(4) >>> print(b_list) [1, 2, 3, 4] >>> print(a_list) [1, 2, 3, 4]
As you can see from the above example even though
was the only list which had an extra element added to it,
Why Does A Copied List Change?
The reason why a list, when “copied” using the approach of
b_list = a_list
, doesn’t work as expected is that the new variable
is assigned the
. It does not create an
of the list.
You can know this by checking the
of each variable.
returns a unique identifier for the variable passed as an argument. This object can be any type of variable, such as a dictionary, a list, a tuple, etc. The returned value is an integer and is guaranteed to be unique and constant for this object during its lifetime.
Using the above example again you can see that when the
variable is assigned
it has the same unique identifier from
>>> a_list = [1, 2, 3] >>> b_list = a_list >>> id(b_list) 140272962785472 >>> id(a_list) 140272962785472 >>> id(b_list) == id(a_list) True
As you can see, both variables have the same
. Therefore, whenever you are “copying” a variable using a simple variable assignment like
b_list = a_list
you now have two unique variables
operating on the same object
Create An Actual Copy Of A List
So how do you create an actual copy of a list without just copying the reference of the original list?
There are several ways to copying a list, each has their unique approaches and constraints, and these are:
- Using the copy.deepcopy() method
empty slice operator
I will demonstrate how you can use each approach with examples.
method in Python
is used to create a
of the original list object. This means that a new object is created containing the same values as the original object and is stored in different memory locations.
This means when you are operating on one list, such as appending or removing items, it will not affect the elements contained in the other.
Here’s an example of how this method works and how it creates a unique
>>> a_list = [1, 2, 3] >>> id(a_list) 140272962785472 >>> b_list = a_copy.copy() >>> id(b_list) 140272962785600 >>> id(a_list) == id(b_list) False
As you can see from the above Python code output the
variable created has its own unique identifier. This means that
can be operated on independent of
meaning that changes made on either
will not change the other.
>>> b_list.append(4) >>> print(b_list) [1, 2, 3, 4] >>> print(a_list) [1, 2, 3]
changes, and the change made to that list doesn’t impact the original
which was copied.
However, there is one thing to be mindful of with the
method: it is a
. This means that the original list contains
(objects that can be changed, for example: lists, dictionaries, etc.).
Shallow Copy Problems
The issue with shallow copying objects is that if the copied object contains mutating objects, like lists or dictionaries, that changes made to those mutating elements in the original list will only be copied as references.
Here’s an example of a simple list with a mutating object within it and how using the
method produces issues:
>>> a_list = [, 2, 3] >>> b_list = a_list.copy() >>> for a in a_list: ... print(id(a)) ... 140272962833984 140272960989520 140272960989552 >>> for b in b_list: ... print(id(b)) ... 140272962833984 140272960989520 140272960989552 >>> id(a_list) == id(b_list) False
As demonstrated in the above code, the two lists both have unique identifiers, which means the contents can change without impacting the other. However, notice the first element in each list points to the same id .
From what you’ve learned at the very start of this article you’ll remember that when items such as lists contain the same id changes made to that object will change the other.
Continuing on from the above code, and modifying that first element produces the following startling result:
>>> a_list.append(2) >>> print(a_list) [[1, 2], 2, 3] >>> print(b_list) [[1, 2], 2, 3] >>> id(a_list) == id(b_list) True
As you can see from the above output the changes performed on the first element in
ended up modifying
even though each list has its own unique identifier!
It’s not until you inspect the first element’s
on both lists that you realise they have the same reference.
This is the one downside when copying lists using the shallow copy
method on your original list: if your original list contains lists or dictionaries (mutatable objects) then these are copied by reference.
So how do you overcome this problem?
This is why another more popular method for copying lists circumvents this issue and is found in the
library. The method is called
If your list contains mutating objects such as lists and dictionaries then would want to prefer the other copying method
For this method to work you will need to import the
at the top of your code before calling the method
Python documentation on
this method constructs its own compound objects from the original list. The best way to demonstrate the difference is through an example very similar to one above:
>>> import copy >>> a_list = [, 2, 3] >>> b_list = copy.deepcopy(a_list) >>> a_list.append(2) >>> print(a_list) [[1, 2], 2, 3] >>> print(b_list) [, 2, 3] >>> id(a_list) 140272962839936 >>> id(b_list) 140272962839040 >>> id(a_list) == id(b_list) False
From the above output from the Python REPL you can see that using
produces a distinct copy of the original list. Even the nested list in the first element of
when amended does not alter the copied
first element, and running the
function on the first element shows they both have unique identifiers.
The only issue with using this option is that it does take longer to perform copies and you will need to remember to import the
library. If speed isn’t a concern and you’re dealing with elements within a list that are likely to be lists or dictionaries then this should be your
preferred method when copying lists
Other List Copying Hacks
There are other techniques to perform shallow copies of a list, while these produce the same result they are different ways of writing it in Python:
Shallow Copy Slice Operator
empty slice operator
performs the same as
as demonstrated below:
>>> a_list = [, 2, 3] >>> b_list = a_list[:] >>> id(a_list) == id(b_list) False >>> id(a_list) == id(b_list) True
As you can see from the example above the newly created
is a shallow copy of the original
but is not a deep copy of the original due to the first element in
being the same as
to the original list is 4 characters too long then you can use this shortcut technique to create a shallow copy of your original list.
The list constructor allows for changing a variable into the list data type . If you’re already inserting a list into the constructor then no real conversion is needed, but it does produce a new shallow copy list, as demonstrated below:
>>> a_list = [, 2, 3] >>> b_list = list(a_list) >>> id(a_list) == id(b_list) False >>> id(a_list) == id(b_list) True
Once again another example of how to create a shallow copy of the original list.
If you want another technique for creating a deep copy of the original list then another approach could be to extract the original list using
(which converts the list to a string) and then to use
to read the string and create another list.
Here’s how this process looks and the resulting
>>> import json >>> a_list = [, 2, 3] >>> b_list = json.loads(json.dumps(a_list)) >>> id(a_list) == id(b_list) False >>> id(a_list) == id(b_list) False
As you can see from this result using the
in combination with the
methods you can achieve a deep copied list that has its own references for the elements in each list.
When assigning a new list variable from an existing one it can be easy to think that the contents of the copied list are cloned into the new list. However, it doesn’t take long until you realise that the new list actually makes changes to the original list!
To make distinct clones of the original list determine whether you will need to do a shallow or deep copy of the list first. Once you know the type of copying you will need to do you can then apply any of the techniques above to accomplish what you need.
Popular shallow copying techniques for lists involve:
. All of these create a shallow copy meaning that if the list contains elements such as lists or dictionaries and these are likely to be modified
the assignment this will change both lists too.
Popular deep copying techniques for lists involve using the
techniques. Each method requires either the