Python Dictionaries: Copy Method Explained
Learn every way to copy a Python dictionary — copy(), dict(), {**d}, and deepcopy() — with clear examples showing shallow vs. deep copy behaviour.
This chapter explains every standard way to copy a Python dictionary, why a plain assignment (=) is not a copy, and when you need a deep copy instead of a shallow one.
Why You Cannot Copy a Dictionary with =
Assigning a dictionary to a new variable does not create a copy — it creates a second reference to the same object. Any change made through either variable affects the same underlying dictionary.
original = {'a': 1, 'b': 2}
alias = original # same object, not a copy
alias['c'] = 3
print(original) # {'a': 1, 'b': 2, 'c': 3} — original changed!To get a genuinely independent dictionary you need one of the copy methods shown below.
Shallow Copy vs. Deep Copy
Before looking at the methods, it helps to understand the two kinds of copy:
| Kind | What is copied | Nested mutables |
|---|---|---|
| Shallow copy | Top-level key-value pairs | References are shared — mutation in one dict affects the other |
| Deep copy | Every object at every depth | Fully independent — no shared references |
For flat dictionaries (values are strings, numbers, None, booleans) a shallow copy is always sufficient. For dictionaries that contain lists, sets, or other dictionaries as values, consider a deep copy.
Method 1: dict.copy()
The built-in copy() method returns a new dictionary that is a shallow copy of the original. It is the most idiomatic choice for flat dictionaries.
Syntax
new_dict = original_dict.copy()Make a shallow copy of a dictionary in Python
Adding or removing a key in new_dict leaves original_dict untouched because the top-level copy is independent.
Updating top-level keys in a copied dictionary
Method 2: dict() Constructor
Passing an existing dictionary to the dict() constructor creates a shallow copy in the same way as copy().
original_dict = {'name': 'Alice', 'age': 30}
new_dict = dict(original_dict)
new_dict['age'] = 31
print(original_dict) # {'name': 'Alice', 'age': 30}
print(new_dict) # {'name': 'Alice', 'age': 31}dict() is useful when you want to be explicit about creating a dictionary from another mapping or when you mix keyword arguments with an existing dictionary:
defaults = {'color': 'blue', 'size': 'M'}
custom = dict(defaults, size='L', weight='light')
print(custom)
# {'color': 'blue', 'size': 'L', 'weight': 'light'}Method 3: Dictionary Unpacking {**d}
The ** unpacking operator merges a dictionary into a new dictionary literal. For a simple copy it behaves identically to copy(), but it also lets you merge several dictionaries or override individual keys in one expression.
original_dict = {'a': 1, 'b': 2}
new_dict = {**original_dict}
new_dict['c'] = 3
print(original_dict) # {'a': 1, 'b': 2}
print(new_dict) # {'a': 1, 'b': 2, 'c': 3}Copying while overriding a key
config = {'host': 'localhost', 'port': 5432, 'debug': False}
prod_config = {**config, 'host': 'db.example.com', 'debug': False}
print(prod_config)
# {'host': 'db.example.com', 'port': 5432, 'debug': False}Like copy(), this is a shallow copy — nested mutables are still shared.
Shallow Copy Gotcha: Nested Mutables Are Shared
All three methods above produce shallow copies. When a value is itself a mutable object (such as a list), both the original and the copy hold a reference to the same inner object.
Updating mutable values inside a copied dictionary
Both dictionaries reflect the change because new_dict['key1'] and original_dict['key1'] point to the same list object. This is expected behaviour for a shallow copy — it is not a bug.
Method 4: copy.deepcopy() for Full Independence
When you need complete isolation — including nested lists, sets, and dictionaries — use copy.deepcopy() from the standard-library copy module. It recursively copies every object in the structure.
Deep copy in Python
deepcopy() handles arbitrarily nested structures and even self-referential objects. Its trade-off is speed and memory: it is slower than a shallow copy because it must traverse and duplicate the entire object graph.
Choosing the Right Method
| Situation | Recommended method |
|---|---|
| Flat dictionary (no nested mutables) | dict.copy() or {**d} |
| Merge / override keys while copying | {**d, key: value} or dict(d, key=value) |
| Nested mutables, need full independence | copy.deepcopy() |
| Convert another mapping to a dict copy | dict(mapping) |
Summary
- The
=operator creates an alias, not a copy. dict.copy(),dict(), and{**d}all produce shallow copies — top-level keys are independent but nested mutables are shared.copy.deepcopy()produces a deep copy — every object at every depth is duplicated.- For flat dictionaries, prefer
dict.copy()for clarity. - Use
{**d, overrides}when you need to copy and modify in a single expression.
See also: Dictionary Methods · Nested Dictionaries · Loop Through Dictionaries