What is the Difference Between Shallow and Deep Copying?

Python tutorial with code examples

What is the Difference Between Shallow and Deep Copying?
Photo by Philipp Katzenberger on Unsplash

Whenever teaching programming, the analogy I use for copying a list is taking a photocopy. It’s a simple, visual example that everybody can relate to. But more importantly, the analogy has a major flaw — intentionally. Unlike a photocopy, there is an additional component to copying lists and any other complex data structure: shallow copying vs deep copying.

In this guide we’ll demonstrate both shallow and deep copying to highlight the difference. Shallow copying is a simpler process so we’ll provide three different techniques for doing so.

Starter Code

We’re going to need some initial starter code to get started. We’re defining a simple class with one attribute name. The __init__ method is executed when an instance of the class is created and the __repr__ method is responsible for defining when an instance of the class is printed.class Person:
 def __init__(self, name):
   self.name = name  def __repr__(self):
   return self.nameteam = [Person("Cloud"), Person("Tifa"), Person("Yuffie)]

We’re going to create a list named team with three instances of our class. This will be used as our base to demonstrate the difference between shallow and deep copy.

How to Shallow Copy

When you shallow copy a list, you are creating a new list that preserves the references of the original list. What this means is that we have two lists which point to the same space in memory.

The dual reference is not an issue with primitive values like strings and integers; however, for complex data such as classes, then we may experience unintended consequences when modifying the list’s values.

Before we dive into all of that, there are three ways to perform a shallow copy.# The .copy() Method
team1 = team.copy()# Slice Notation
team2 = team[:]# Splat Operator
team3 = [*team]

Conveniently, lists have a predefined method named .copy() for a simple shallow copy. Slice notation can also be used to functionally create a shallow copy and is a helpful notation to familiarize yourself with if you need to take portions of lists. Finally, the splat operator can be used to unpack our original list into a new one and is helpful for copying and extending a list.

Now, back to the problem with a shallow copy. Since both lists point to the same instance of an object, when the object is changed in one list, it will be changed in the other as well. The implication is that our copied list cannot be manipulated with impunity.

How to Deep Copy

A deep copy is required to create a list that is truly independent of its originator. Unlike the techniques for shallow copying, a deep copy requires the use of an imported library — take a look at the starter code if you missed that.

Within the copy library, we import the deepcopy() function. From here, it’s simple to use. Let’s demonstrate a deep copy and then finally see the difference between shallow and deep by making a change to our original team.team4 = deepcopy(team)team[0].name = "Cid"print(team1, team2, team3, team4, sep="\n")
"""
[Cid, Tifa, Yuffie]
[Cid, Tifa, Yuffie]
[Cid, Tifa, Yuffie]
[Cloud, Tifa, Yuffie]
"""

After changing the first index in our original list, we print our four copied lists and only the deep copied list maintains its original values.


In closing, when you think of photocopying a list, this is a functional example of a deep copy — a distinct, completely separate entity has been created. When conceptualizing shallow copying, think of a cloud document where multiple entities can access it; however, when one changes “their copy” everybody else takes the update as well.


Thanks for reading. Please share your experiences, questions, and feedback below!

Subscribe to Dreams of Fortunes and Cookies

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe