How to avoid "RuntimeError: dictionary changed size during iteration" error?
Categories:
How to Avoid 'RuntimeError: dictionary changed size during iteration' in Python

Learn why Python's dictionaries throw a RuntimeError when modified during iteration and discover robust strategies to prevent this common issue.
The RuntimeError: dictionary changed size during iteration
is a common exception encountered by Python developers. This error occurs when you attempt to modify a dictionary (e.g., add, remove, or change items) while you are actively iterating over it. Python's design philosophy prioritizes predictable behavior and prevents potential inconsistencies that could arise from such modifications, leading to this explicit error.
Understanding the Problem
When you iterate over a dictionary, Python creates an internal view of its items. If the dictionary's size changes during this process, the internal view becomes invalid, and Python raises a RuntimeError
to prevent unexpected behavior or data corruption. This is a safety mechanism, not a bug. It applies to direct iteration using for key in dict:
or for key, value in dict.items():
.
my_dict = {'a': 1, 'b': 2, 'c': 3}
for key, value in my_dict.items():
if key == 'b':
my_dict['d'] = 4 # This will raise RuntimeError
print(f"{key}: {value}")
Example of code that will cause 'RuntimeError: dictionary changed size during iteration'
flowchart TD A[Start Iteration] --> B{Dictionary Modified?} B -- Yes --> C["RuntimeError: dictionary changed size during iteration"] B -- No --> D[Continue Iteration] D --> E{End of Dictionary?} E -- No --> A E -- Yes --> F[Iteration Complete]
Flowchart illustrating when the RuntimeError occurs during dictionary iteration
Effective Solutions
There are several robust ways to modify a dictionary while iterating, each suited for different scenarios. The key is to avoid direct modification of the dictionary being iterated.
1. Iterate Over a Copy
The simplest and often most straightforward solution is to iterate over a copy of the dictionary's keys, values, or items. This allows you to safely modify the original dictionary without affecting the iteration process.
my_dict = {'a': 1, 'b': 2, 'c': 3}
# Iterate over a copy of keys
for key in list(my_dict.keys()):
if key == 'b':
my_dict['d'] = 4 # Safe to add
elif key == 'c':
del my_dict[key] # Safe to delete
print(f"Processing key: {key}")
print(f"Modified dictionary: {my_dict}")
Modifying a dictionary by iterating over a copy of its keys
2. Build a New Dictionary
If your modifications are complex or involve creating a significantly different structure, it's often cleaner to build a new dictionary based on the original, applying your logic during its construction. This approach is particularly useful when filtering or transforming items.
original_dict = {'apple': 1, 'banana': 2, 'cherry': 3, 'date': 4}
new_dict = {}
for key, value in original_dict.items():
if value % 2 == 0: # Keep even values
new_dict[key] = value
if key == 'banana': # Add a new item based on a condition
new_dict['grape'] = 5
print(f"Original dictionary: {original_dict}")
print(f"New dictionary: {new_dict}")
Building a new dictionary with filtered and added items
3. Store Keys for Deletion/Modification
If you only need to delete or modify specific items, you can collect the keys of the items to be acted upon during the first pass, and then perform the actual modifications in a second pass.
my_dict = {'item1': 10, 'item2': 20, 'item3': 30, 'item4': 40}
keys_to_delete = []
keys_to_update = {}
# First pass: identify changes
for key, value in my_dict.items():
if value > 25:
keys_to_delete.append(key)
elif value == 20:
keys_to_update[key] = value * 2
# Second pass: apply changes
for key in keys_to_delete:
del my_dict[key]
for key, new_value in keys_to_update.items():
my_dict[key] = new_value
print(f"Final dictionary: {my_dict}")
Collecting keys for modification in a separate pass
dict.keys()
directly might seem safe because you're not iterating over dict.items()
, it's still iterating over a view that can become invalid if the dictionary's size changes. Always use list(dict.keys())
or list(dict.items())
for safety.