How to copy a dictionary and only edit the copy
Categories:
How to Safely Copy a Python Dictionary and Edit the Copy

Learn the correct methods to create independent copies of Python dictionaries, ensuring modifications to the copy do not affect the original dictionary. This guide covers shallow and deep copying techniques.
When working with dictionaries in Python, it's common to need a separate, editable version without altering the original. Directly assigning one dictionary to another (new_dict = original_dict
) does not create a copy; instead, it creates a new reference to the same dictionary object. This means any changes made through new_dict
will also affect original_dict
.
Understanding References vs. Copies
In Python, variables don't store objects directly; they store references to objects. When you assign dict_b = dict_a
, both dict_a
and dict_b
point to the exact same dictionary in memory. This behavior is crucial to understand when you intend to modify a dictionary independently.
graph TD A[Original Dictionary] --> B(Memory Address X) C[Reference 1 (original_dict)] --> B D[Reference 2 (new_dict)] --> B B -- "Modification via Reference 2" --> B B -- "Affects Reference 1" --> B
Illustrating how direct assignment creates multiple references to the same dictionary object.
original_dict = {'a': 1, 'b': 2}
new_dict = original_dict
new_dict['c'] = 3
print(f"Original dict: {original_dict}")
print(f"New dict: {new_dict}")
# Output:
# Original dict: {'a': 1, 'b': 2, 'c': 3}
# New dict: {'a': 1, 'b': 2, 'c': 3}
Demonstration of how direct assignment leads to shared modifications.
Shallow Copies for Simple Dictionaries
For dictionaries containing only immutable values (like numbers, strings, tuples), a shallow copy is sufficient. A shallow copy creates a new dictionary object, but it populates the new dictionary with references to the same objects that the original dictionary contains. If the values are immutable, this is not an issue, as they cannot be changed in place.
graph TD A[Original Dictionary] --> B(Memory Address X) B -- "Key 'a'" --> C(Value 1) B -- "Key 'b'" --> D(Value 2) E[Shallow Copy] --> F(Memory Address Y) F -- "Key 'a'" --> C F -- "Key 'b'" --> D subgraph Original Modification B -- "Add Key 'c'" --> G(Value 3) end subgraph Copy Modification F -- "Add Key 'd'" --> H(Value 4) end
How a shallow copy creates a new dictionary object with references to the original values.
# Method 1: Using the .copy() method
original_dict_1 = {'name': 'Alice', 'age': 30}
copy_dict_1 = original_dict_1.copy()
copy_dict_1['age'] = 31
print(f"Original 1: {original_dict_1}") # {'name': 'Alice', 'age': 30}
print(f"Copy 1: {copy_dict_1}") # {'name': 'Alice', 'age': 31}
# Method 2: Using the dict() constructor
original_dict_2 = {'city': 'New York', 'zip': '10001'}
copy_dict_2 = dict(original_dict_2)
copy_dict_2['zip'] = '10002'
print(f"Original 2: {original_dict_2}") # {'city': 'New York', 'zip': '10001'}
print(f"Copy 2: {copy_dict_2}") # {'city': 'New York', 'zip': '10002'}
# Method 3: Using dictionary unpacking (Python 3.5+)
original_dict_3 = {'item': 'apple', 'price': 1.50}
copy_dict_3 = {**original_dict_3}
copy_dict_3['price'] = 2.00
print(f"Original 3: {original_dict_3}") # {'item': 'apple', 'price': 1.50}
print(f"Copy 3: {copy_dict_3}") # {'item': 'apple', 'price': 2.00}
Three common ways to create a shallow copy of a dictionary.
Deep Copies for Nested Dictionaries
When a dictionary contains mutable objects as values (e.g., lists, other dictionaries, sets), a shallow copy is not enough. Modifying these nested mutable objects in the copy will still affect the original, because both dictionaries hold references to the same nested objects. To truly isolate the copy, you need a deep copy.
copy.deepcopy()
only when necessary.graph TD A[Original Dictionary] --> B(Memory Address X) B -- "Key 'data'" --> C(Memory Address Z: Nested List) C -- "Index 0" --> D(Value 1) E[Shallow Copy] --> F(Memory Address Y) F -- "Key 'data'" --> C subgraph Shallow Copy Modification F -- "Modify C via 'data'" --> C C -- "Change Index 0" --> E(New Value 1) end style A fill:#f9f,stroke:#333,stroke-width:2px style E fill:#ccf,stroke:#333,stroke-width:2px
How a shallow copy fails with nested mutable objects: both dictionaries reference the same nested list.
import copy
original_nested_dict = {
'user': 'John Doe',
'settings': {'theme': 'dark', 'notifications': True},
'items': ['apple', 'banana']
}
# Shallow copy
shallow_copy = original_nested_dict.copy()
shallow_copy['settings']['theme'] = 'light' # Modifies original!
shallow_copy['items'].append('orange') # Modifies original!
print(f"Original after shallow: {original_nested_dict}")
# Output: {'user': 'John Doe', 'settings': {'theme': 'light', 'notifications': True}, 'items': ['apple', 'banana', 'orange']}
# Deep copy
deep_copy = copy.deepcopy(original_nested_dict)
deep_copy['settings']['theme'] = 'blue' # Only modifies deep_copy
deep_copy['items'].append('grape') # Only modifies deep_copy
print(f"Original after deep: {original_nested_dict}")
# Output: {'user': 'John Doe', 'settings': {'theme': 'light', 'notifications': True}, 'items': ['apple', 'banana', 'orange']}
print(f"Deep copy: {deep_copy}")
# Output: {'user': 'John Doe', 'settings': {'theme': 'blue', 'notifications': True}, 'items': ['apple', 'banana', 'orange', 'grape']}
Comparing shallow vs. deep copy behavior with nested mutable objects.
graph TD A[Original Dictionary] --> B(Memory Address X) B -- "Key 'data'" --> C(Memory Address Z: Nested List) C -- "Index 0" --> D(Value 1) E[Deep Copy] --> F(Memory Address Y) F -- "Key 'data'" --> G(Memory Address W: New Nested List) G -- "Index 0" --> H(Value 1) subgraph Deep Copy Modification F -- "Modify G via 'data'" --> G G -- "Change Index 0" --> I(New Value 1) end style A fill:#f9f,stroke:#333,stroke-width:2px style E fill:#ccf,stroke:#333,stroke-width:2px
How a deep copy creates entirely new objects for all nested mutable structures.