When working with a dictionary in Python, you might encounter the following error:
RuntimeError: dictionary changed size during iteration
This error usually occurs when you try to add or remove items from a dictionary that you’re iterating over with a for
loop.
The following tutorial shows an example that causes this error and how to fix it.
How to reproduce this error
Suppose you have a dictionary that has some empty values as follows:
my_dict = {"a": 123, "b": 0, "c": 778, "d": 0}
The my_dict
dictionary has some entries that contain 0
values, and you want to remove those entries from the dictionary.
You used a for
loop to iterate over the dictionary and remove entries with 0
values:
for key in my_dict:
if my_dict[key] == 0:
my_dict.pop(key)
print(my_dict)
But Python doesn’t allow you to change the size of a dictionary inside an iteration such as a for
loop, so you get the following error:
Traceback (most recent call last):
File "main.py", line 3, in <module>
for key in my_dict:
RuntimeError: dictionary changed size during iteration
The error message refers to the line for key in my dict:
, but the actual error occurs when my dict.pop(key)
is executed and the dictionary size is changed.
This is because if you can change the size of a dictionary inside a for
loop, then you can run the loop endlessly as demonstrated in the following example:
my_dict = {"a": 123}
for key in my_dict:
rand = random.randint(0,50)
data[rand] = rand
In the code above, a random number is added to the dictionary inside the for
loop, which increases the size of the dictionary and causes the loop to never end.
How to fix this error
To resolve this error, you need to avoid changing the size of the dictionary in the for
loop.
This can be done by extracting the dictionary keys as a list, then you loop over that list instead of the dictionary:
my_dict = {"a": 123, "b": 0, "c": 778, "d": 0}
# Get dictionary keys as a list
dict_keys = list(my_dict)
print(dict_keys) # ['a', 'b', 'c', 'd']
for key in dict_keys:
if my_dict[key] == 0:
my_dict.pop(key)
print(my_dict) # {'a': 123, 'c': 778}
As long as you’re not looping over the dictionary itself, then the error won’t be raised.
If you want to keep the original dictionary, you can copy the items that you want to keep to a new dictionary using a for
loop as follows:
my_dict = {"a": 123, "b": 0, "c": 778, "d": 0}
# An empty dictionary to copy relevant entries
new_dict = {}
for key in my_dict:
if my_dict[key] != 0:
new_dict[key] = my_dict[key]
print(new_dict) # {'a': 123, 'c': 778}
You can also use a dictionary comprehension syntax, even though it’s harder to read as follows:
my_dict = {"a": 123, "b": 0, "c": 778, "d": 0}
new_dict = { k: v for k, v in my_dict.items() if v != 0 }
print(new_dict) # {'a': 123, 'c': 778}
It’s okay to loop over a dictionary as long as you’re not changing the size of that dictionary in the for
loop body.
I hope this tutorial is helpful. See you in other tutorials! 🙌