How to Deep Copy a Dictionary in Python 3 with Nested Objects
Learn the correct way to create a deep copy of Python dictionaries including nested lists. Use copy.deepcopy() to avoid shared references.
How to create a deep copy of a dictionary in Python 3.x, including nested mutable objects like lists?
Consider this example:
>>> my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
>>> my_copy = my_dict.copy()
>>> my_dict['a'][2] = 7
>>> my_copy['a'][2]
7
The output should be 3 for a true deep copy. Modifications to nested lists in my_dict should not affect my_copy. Note that dict has no deepcopy() method:
>>> my_copy = my_dict.deepcopy()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'deepcopy'
What is the correct way to achieve a deep copy compatible with Python 3.x?
To create a deep copy of a dictionary in Python 3.x including nested mutable objects like lists, import the copy module and use copy.deepcopy(my_dict). This recursively copies all nested structures, so changes to lists inside the original—like setting my_dict['a'][2] = 7—won’t touch the copy, keeping my_copy['a'][2] as 3. Shallow methods like dict.copy() or dict(my_dict) fail here because they only duplicate top-level keys, sharing references to inner mutables.
Contents
- What is a Deep Copy in Python?
- Why dict.copy() Fails for Nested Objects
- How to Use copy.deepcopy() for Deep Copy
- Complete Example: Deep Copy of Dict with Nested Lists
- Alternatives to deepcopy
- Best Practices and Edge Cases
- Sources
- Conclusion
What is a Deep Copy in Python?
Ever copied a dictionary thinking you’re safe, only to watch changes ripple through both? That’s the shallow vs. deep copy trap. A shallow copy duplicates only the top level—like my_dict.copy()—but nested objects (lists, dicts) stay linked by reference. Mess with a list inside, and both copies feel it.
Deep copy? It clones everything, recursively. Your example nails it: {'a': [1,2,3]} becomes fully independent. The Python docs on copy spell this out: deepcopy(x, memo=None) traverses the object graph, creating fresh mutables at every level. No more shared innards.
Quick comparison:
| Method | Copies Nested Mutables? | Your Example Result |
|---|---|---|
dict.copy() |
No (shallow) | my_copy['a'][2] → 7 |
{**my_dict} |
No (shallow) | my_copy['a'][2] → 7 |
copy.deepcopy() |
Yes (deep) | my_copy['a'][2] → 3 |
Why care? Nested data is everywhere—configs, JSON parses, game states. Get this wrong, and debugging turns nightmare-ish.
Why dict.copy() Fails for Nested Objects
Your code demo is textbook. Run it:
my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
my_copy = my_dict.copy()
my_dict['a'][2] = 7
print(my_copy['a'][2]) # Outputs: 7 😱
That 7 screams “shared reference.” Dictionaries hold pointers to lists. copy() clones the dict shell, but points both to the same list object. Mutate it? Both hurt.
No dict.deepcopy() exists—Python skips it to avoid bloat, pushing you to the copy module. Sites like note.nkmk.me recreate your exact fail, proving it’s not user error. Even dict(my_dict) or my_dict | {} acts shallow. Sneaky, right?
But what if no nests? Shallow wins—faster, lighter. Here? Deep or bust.
How to Use copy.deepcopy() for Deep Copy
Simple fix. Two lines:
import copy
my_copy = copy.deepcopy(my_dict)
That’s it for Python 3.x (works 3.6+ seamlessly). deepcopy digs in: hits a list? Copies it. Hits a dict inside? Copies that too. Cycles? Uses a memo dict to avoid infinite loops.
From the official docs: “Creates new compound objects and recurses.” Handles custom classes if they define __copy__ or __deepcopy__. Skips modules, files—can’t copy those sanely.
Test it quick:
import copy
my_dict = {'a': [1, 2, 3]}
my_copy = copy.deepcopy(my_dict)
my_dict['a'][2] = 7
print(my_copy['a'][2]) # 3 ✅
print(my_dict['a'][2]) # 7 ✅
Independent. Beautiful.
Complete Example: Deep Copy of Dict with Nested Lists
Your full case, solved. Copy-paste ready:
import copy
my_dict = {'a': [1, 2, 3], 'b': [4, 5, 6]}
my_copy = copy.deepcopy(my_dict)
# Mutate original
my_dict['a'][2] = 7
my_dict['b'].append(99)
print("Original:", my_dict)
# {'a': [1, 2, 7], 'b': [4, 5, 6, 99]}
print("Copy:", my_copy)
# {'a': [1, 2, 3], 'b': [4, 5, 6]}
print("Copy 'a'[2]:", my_copy['a'][2]) # 3
Matches Stack Overflow examples and labex.io tutorials. Nested deeper? Still safe. Add {'c': {'x': [10]}}—deepcopy handles it.
Pro tip: id() confirms separation.
print(id(my_dict['a']) == id(my_copy['a'])) # False
New objects. Done.
Alternatives to deepcopy
Deepcopy rocks, but heavy for big data. Options?
-
JSON hack (simple nests only):
import json; my_copy = json.loads(json.dumps(my_dict)). Fast, but chokes on non-JSON (functions, classes). GeeksforGeeks covers pitfalls. -
Manual recursion: Fun for control.
def deep_copy(obj):
if isinstance(obj, dict):
return {k: deep_copy(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [deep_copy(i) for i in obj]
return obj
my_copy = deep_copy(my_dict)
From Stack Overflow nested threads. Scales to sets, tuples—customize away.
- Pickle:
import pickle; my_copy = pickle.loads(pickle.dumps(my_dict)). Serializes everything, but insecure for untrusted data.
Deepcopy safest default. Others? When you know your data shape.
Best Practices and Edge Cases
- Immutables? Shallow = deep.
{'a': (1,2)}—tuples don’t mutate. - Performance: Deepcopy O(n) time/space. Big nests? Profile first. Reddit threads like r/learnpython note this.
- Custom objects: Define
__deepcopy__in your class. - Edge bombs: Self-referential dicts (deepcopy memos them). File objects? Raises error—handle manually.
- Python 3.x only: All good, no 2.x worries.
Stuck? copy.copy() for shallow fallback. Questions like yours pop up tons—test in REPL.
Sources
- copy — Shallow and deep copy operations — Official Python 3 docs on deepcopy mechanics and usage: https://docs.python.org/3/library/copy.html
- Shallow copy, deep copy in Python — Exact example matching query with nested lists: https://note.nkmk.me/en/python-copy-deepcopy/
- Deep copy of a dict in python — Stack Overflow discussion with code solutions for nested dicts: https://stackoverflow.com/questions/5105517/deep-copy-of-a-dict-in-python
- Nested dictionaries: copy or deepcopy? — Explains reference sharing in shallow copies of nested structures: https://stackoverflow.com/questions/39474959/nested-dictionaries-copy-or-deepcopy
- How to Create Deep Copy of Dictionaries — Tutorial with complex nested examples and verification: https://labex.io/tutorials/python-how-to-create-deep-copy-of-dictionaries-419728
- Deep Copy of a Dictionary in Python — Overview of pitfalls and JSON alternative: https://www.geeksforgeeks.org/python/deep-copy-of-a-dictionary-in-python/
Conclusion
For reliable deep copies of Python dictionaries with nested lists or mutables, copy.deepcopy() is your go-to—fixes your example perfectly, keeping copies isolated. Skip shallow tricks unless data’s flat. Experiment with the code above; it’ll save headaches down the line. Questions? Dive into the docs.