Question
In Python, assigning one list variable to another does not create a separate copy. Why does this happen, and how can you clone or copy a list so changes to the new list do not affect the original?
Example:
my_list = [1, 2, 3]
new_list = my_list
new_list.append(4)
print(my_list)
Output:
[1, 2, 3, 4]
How can you create a true copy of the list instead of another reference to the same list?
Short Answer
By the end of this page, you will understand why new_list = my_list does not copy a list in Python, how list references work, and how to make shallow and deep copies safely depending on the kind of data your list contains.
Concept
In Python, variables do not store objects directly in the way many beginners imagine. Instead, a variable holds a reference to an object.
When you write:
new_list = my_list
both variables point to the same list object in memory. That means there is only one list, and both names refer to it. If you modify that list through either variable, the change is visible through the other.
This matters because lists are mutable, which means they can be changed after creation. Methods like append(), remove(), sort(), and item assignment all modify the existing list.
To avoid unwanted shared changes, you must create a copy.
There are two important kinds of copying in Python:
- Shallow copy: creates a new outer list, but nested objects inside it are still shared.
- Deep copy: creates a completely independent copy, including nested lists or other nested mutable objects.
For a simple flat list like [1, 2, 3], a shallow copy is usually enough. For nested structures like [[1, 2], [3, 4]], you may need a deep copy.
This concept appears everywhere in real Python code because accidental shared mutation can cause bugs that are hard to trace.
Mental Model
Think of a Python list like a physical notebook.
my_listis a label stuck on the notebook.new_list = my_listdoes not make a second notebook.- It just puts a second label on the same notebook.
So if you write something in the notebook using either label, both labels still point to that same updated notebook.
If you want an independent notebook, you must make a photocopy.
- A shallow copy is like copying only the main pages, but any attached inserts are still shared.
- A deep copy is like copying everything, including all inserts and attachments.
Syntax and Examples
Basic assignment does not copy
my_list = [1, 2, 3]
new_list = my_list
new_list.append(4)
print(my_list) # [1, 2, 3, 4]
print(new_list) # [1, 2, 3, 4]
Both variables refer to the same list.
Shallow copy methods
Using slicing
my_list = [1, 2, 3]
new_list = my_list[:]
new_list.append(4)
print(my_list) # [1, 2, 3]
print(new_list) # [1, 2, 3, 4]
Using list()
my_list = [1, 2, 3]
new_list = list(my_list)
Using .copy()
my_list = [1, 2, 3]
new_list = my_list.copy()
All three create a new outer list.
Step by Step Execution
Consider this code:
my_list = [1, 2, 3]
new_list = my_list
new_list.append(4)
print(my_list)
Step by step:
-
my_list = [1, 2, 3]- Python creates one list object containing
1,2, and3. - The name
my_listpoints to that list.
- Python creates one list object containing
-
new_list = my_list- No new list is created.
new_listnow points to the exact same list asmy_list.
-
new_list.append(4)- The shared list is modified in place.
- Since both variables point to the same object, both now see
[1, 2, 3, 4].
-
print(my_list)- Output is:
Real World Use Cases
Copying lists is common in real programs when you want to work with data safely without mutating the original.
Common situations
-
Processing user input
- Keep the original values unchanged while transforming a copy.
-
Sorting data for display
- Show a sorted version of a list without changing the original order.
scores = [88, 72, 95]
sorted_scores = scores.copy()
sorted_scores.sort()
-
Undo or history features
- Save a snapshot of a list before making changes.
-
API or function safety
- Prevent a function from accidentally modifying a list passed by the caller.
-
Data pipelines
- Transform intermediate results without corrupting source data.
-
Testing
- Create clean copies of test data so one test does not affect another.
Real Codebase Usage
In real projects, developers often copy lists to avoid side effects and make code easier to reason about.
Common patterns
Defensive copying in functions
def add_item(items, item):
items = items.copy()
items.append(item)
return items
This prevents the caller's original list from being changed.
Copy before sorting or modifying
def get_sorted_names(names):
result = names.copy()
result.sort()
return result
Guarding against nested mutation
If the data contains nested lists or dictionaries, developers often use copy.deepcopy() when full independence is required.
import copy
config_copy = copy.deepcopy(config)
Working with transformations
Sometimes developers avoid mutation entirely and build a new list instead:
numbers = [1, 2, 3]
doubled = [n * 2 for n in numbers]
Common Mistakes
1. Thinking assignment creates a copy
Broken example:
a = [1, 2, 3]
b = a
b.append(4)
print(a) # Unexpectedly [1, 2, 3, 4]
Fix:
a = [1, 2, 3]
b = a.copy()
2. Using a shallow copy for nested data
Broken example:
a = [[1], [2]]
b = a.copy()
b[0].append(99)
print(a) # [[1, 99], [2]]
Fix:
import copy
a = [[1], [2]]
b = copy.deepcopy(a)
3. Confusing rebinding with mutation
This does not modify the original list:
a = [1, 2, 3]
b = a
b = [9, 9, ]
(a)
Comparisons
| Approach | Creates new outer list? | Copies nested objects too? | Best for |
|---|---|---|---|
b = a | No | No | Just another reference |
a[:] | Yes | No | Simple shallow copy |
list(a) | Yes | No | Copying any iterable into a list |
a.copy() | Yes | No | Clear shallow copy of a list |
copy.deepcopy(a) | Yes | Yes | Nested mutable data |
Cheat Sheet
Quick reference
Assignment
b = a
- No copy is made
aandbpoint to the same list
Shallow copy
b = a.copy()
b = a[:]
b = list(a)
- New outer list
- Nested mutable items are still shared
Deep copy
import copy
b = copy.deepcopy(a)
- Fully independent copy
- Use for nested lists or dictionaries
Rule of thumb
- Use
a.copy()for normal flat lists - Use
copy.deepcopy(a)for nested mutable data - Do not use
b = aif you need independence
Common mutating list methods
append()
extend()
insert()
remove()
pop()
sort()
reverse()
These change the existing list.
Safe pattern
FAQ
Why does new_list = my_list change both lists in Python?
Because it does not create a new list. It makes both variables refer to the same list object.
What is the best way to copy a list in Python?
For most flat lists, my_list.copy() is the clearest choice.
What is the difference between shallow copy and deep copy?
A shallow copy duplicates only the outer list. A deep copy also duplicates nested mutable objects.
Is slicing like my_list[:] a real copy?
Yes, it creates a shallow copy of the list.
When do I need copy.deepcopy()?
Use it when your list contains nested lists, dictionaries, or other mutable objects that must not be shared.
Does list(my_list) copy the list?
Yes, it creates a shallow copy when my_list is already a list.
Which list operations modify the original list?
Methods like append(), extend(), remove(), sort(), and reverse() modify the list in place.
Mini Project
Description
Build a small Python script that manages a shopping list and creates a safe backup before making changes. This demonstrates the difference between simple assignment and actual copying, and shows why copying matters when you want to preserve original data.
Goal
Create a program that keeps an original shopping list unchanged while modifying a copied version.
Requirements
- Create an original shopping list with at least three items.
- Make one variable using direct assignment and another using a real copy.
- Modify both new variables in different ways.
- Print all lists so the difference is visible.
- Add one nested-list example to demonstrate when
deepcopy()is needed.
Keep learning
Related questions
@staticmethod vs @classmethod in Python Explained
Learn the difference between @staticmethod and @classmethod in Python with clear examples, use cases, mistakes, and a mini project.
Catch Multiple Exceptions in One except Block in Python
Learn how to catch multiple exceptions in one Python except block using tuples, with examples, mistakes, and real-world usage.
Convert Bytes to String in Python 3
Learn how to convert bytes to str in Python 3 using decode(), text mode, and proper encodings with practical examples.