Code Fix

上級

RuntimeError: dictionary changed size during iteration の原因と直し方

辞書をイテレート中にキーを追加・削除すると発生する例外です。リストと違い、辞書はサイズの変化を検出して例外を投げます。

エラーメッセージの読み方

Traceback (most recent call last):
main.py
ファイル名
2
行番号 — 実際にクラッシュした行
<module>
発生場所 — <module> ならトップレベル、関数名ならその関数の中
RuntimeError
例外クラス — 何が起きたか。ここを検索するのが最短です
dictionary changed size during iteration
詳細メッセージ — どの値が問題だったか

このエラーが出る典型パターン

パターン1

 1  scores = {"a": 1, "b": 0, "c": 3}
 2  for key in scores         :
                      ^
 3      if scores[key] == 0:
 4          del scores[key]
 5  print(scores)
Traceback (most recent call last): File "main.py", line 2, in <module> for key in scores: ^^^^^^ RuntimeError: dictionary changed size during iteration

辞書はイテレート中にサイズが変わることを検出すると例外を投げます。安全に削除するには、先にキーのコピー(list())を作ってそちらをイテレートします。

直し方: scoreslist(scores) にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  inventory = {"apple": 5, "banana": 0, "cherry": 2}
 2  for item in inventory         :
                         ^
 3      if inventory[item] == 0:
 4          del inventory[item]
 5  print(inventory)
Traceback (most recent call last): File "main.py", line 2, in <module> for item in inventory: ^^^^^^^^^ RuntimeError: dictionary changed size during iteration

在庫が0の商品を削除するような処理でよく起きます。辞書のキー一覧を先にlist()でコピーしておけば安全です。

直し方: inventorylist(inventory) にします。

この問題を解いてみる →

パターン3

 1  settings = {"a": True, "b": False, "c": True}
 2  for key in settings         :
                       ^
 3      if not settings[key]:
 4          del settings[key]
 5  print(settings)
Traceback (most recent call last): File "main.py", line 2, in <module> for key in settings: ^^^^^^^^ RuntimeError: dictionary changed size during iteration

真偽値フラグの整理でも同じです。Falseの項目を削除する処理はよく書かれるパターンなので、覚えておくと役に立ちます。

直し方: settingslist(settings) にします。

この問題を解いてみる →

よくある誤解

リストの要素削除は例外にならず静かに壊れますが、辞書は検出して例外を投げてくれます。この挙動の違いを知らないと混乱します。

まとめ

RuntimeError: dictionary changed size during iterationは上級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)