How to fix RuntimeError: dictionary changed size during iteration

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! 🙌

Take your skills to the next level ⚡️

I'm sending out an occasional email with the latest tutorials on programming, web development, and statistics. Drop your email in the box below and I'll send new stuff straight into your inbox!

No spam. Unsubscribe anytime.