1. ホーム
  2. プログラミング言語
  3. パイソン

Python辞書ループ RuntimeError: 反復中に辞書のサイズが変更されたエラー解析

2022-01-21 13:19:21

Python


上記のような状況で、プログラムを実行すると、エラーは次のように報告されます。 RuntimeError: dictionary changed size during iteration

分析

Pythonの辞書は、ハッシュテーブルを使って実装されていることが分かっています。ハッシュテーブルは、キーにハッシュ関数を適用してインデックスを取得する配列です。 for cn_id in cn_map_info: この方法では、辞書はイテレータによって走査されますが、要素の追加や削除など走査の途中で変更すると、走査が終了して dictionary changed size during iteration 例外が発生します。

通常の使用では、Pythonはイテレータを使用することを推奨していることを知っています。 for k in xdict という形式をとります。次に、トラバーサル中にコンテナ内の要素を削除することは、C++ STL や Python のようなライブラリでは推奨されません。これは、しばしば設計ソリューションに問題があることを示しているからで、Python に対応する特別な要件として、すべてのライブラリで xdict.key() を使用してコピーを作成します。最後に、すべてのPythonコンテナはスレッドセーフを約束していません。複数のスレッドでこれを行う必要があり、それ自体がロックされていなければならないことも、ビジネスコードの設計に問題があることを示しています。

しかし、"traversal" で特定の要素を削除するという特殊なケースから、"dict のトラバースでは、" の使用が発生します。 for k in d.keys() という習慣がありますが、通常のトラバーサルでは、やはり for k in xdict 効率的なPythonicのアプローチ。

また、"traversal"で要素を削除する必要がある場合、Pythonicのアプローチは xdict = {k, v for adict.iteritems() if v ! = 0} または alist = [i for i in alist if i ! = 0]

Python辞書の実装原理。 https://harveyqing.gitbooks.io/python-read-and-write/content/python_advance/python_dict_implementation.html

解決方法

解決策は、辞書のキーを基準にして、値を変えても反復処理の継続に影響しないように反復処理することです。

Python2 解決方法は以下の通りです。

for cn_id in cn_map_info.keys():
    if cn_id not in monitor_id_list:
        del(cn_map_info[cn_id])

for cn_id in cn_map_info.keys()

key この方法は、リストを経由して、それぞれの for cn_id in list(cn_map_info.keys()): if cn_id not in monitor_id_list: del(cn_map_info[cn_id]) (cn_map_info.keys()が返すリスト)のように、トラバーサル処理が暴走しないようにするためです。

パイソン3 解決方法は以下の通りです。

nock:lab nock$ python2.6
Python 2.6.9 (unknown, Jul 14 2015, 19:46:31) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> monitor_id_list = [12, 13, 14, 16, 19, 20]
>>> cn_map_info = {12: 'taiwan', 13: 'hongkong', 15: 'guizhou'}
>>> print(cn_map_info.keys())
[12, 13, 15]
>>> exit()

nock:lab nock$ python3
Python 3.5.1 (default, Dec 26 2015, 18:08:53) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> monitor_id_list = [12, 13, 14, 16, 19, 20]
>>> cn_map_info = {12: 'taiwan', 13: 'hongkong', 15: 'guizhou'}
>>> print(cn_map_info.keys())
dict_keys([12, 13, 15])
>>> print(list(cn_map_info.keys()))
[12, 13, 15]


繰り返しますが、Python3はリスト内のすべてのキーをループします。これは元の辞書と衝突しないので、探索がクラッシュすることはありません。

なぜPython 3ではlist()が必要なのですか? 解析 は以下の通りです。

xdict.keys()

Python2 では、問題は単純明快です。 xdict.keys() はリストを直接返しますが、Python3 では xdict.keys() は辞書のキーオブジェクトを返します。

この記事を書いたのは 空洞化 で作成した クリエイティブ・コモンズ・ライセンス 4.0 ライセンスに関する国際ライセンス
当サイトに掲載されている記事は、特に断りのない限り、すべてオリジナルまたは翻訳であり、転載の際には必ず属性を明記してください
最終編集日 2018年04月17日 01時07分