10

Python 3.2weakrefモジュールのドキュメントにはWeakKeyDictionaryWeakValueDictionaryこれらのコンテナーの反復処理に関するメモがあります。

注:注意: WeakKeyDictionary は Python ディクショナリの上に構築されるため、反復処理中にサイズを変更してはなりません。WeakKeyDictionary の場合、反復中にプログラムによって実行されるアクションによって、ディクショナリ内の項目が「魔法のように」(ガベージ コレクションの副作用として) 消失する可能性があるため、これを保証するのは難しい場合があります。

これらのコンテナーの動作の仕様としては、かなり悲惨なようです。特に、CPython のガベージ コレクターを使用するコードを実行する場合 (サイクルを含むデータ構造を使用する場合)、または別の Python 実装 (Jython など) を使用する場合、これらのコレクションを安全に反復処理する方法がないように思えます。

ガベージ コレクターがプログラムの任意の時点で参照をクリアする可能性がある場合、これらのコレクションを安全に反復処理するにはどうすればよいですか? CPython のソリューションを持つことが私の優先事項ですが、他の実装の問題にも興味があります。

これは、WeakKeyDictionary を反復処理する安全な方法でしょうか?

import weakref

d = weakref.WeakKeyDictionary()

...

for k, v in list(d.items()):
    ...
4

4 に答える 4

7

安全のために、どこかに参照を保持する必要があります。イディオムの使用:

for k,v in list(d.items()):

ほとんどの場合は機能しますが、ループの最後の反復中にリストがガベージコレクションされる可能性があるため、完全に安全ではありません。

正しい方法は次のとおりです。

items = list(d.items())
for k,v in items:
    #do stuff that doesn't have a chance of destroying "items"
del items

を使用するWeakKeyDictionary場合は、単にキーを保存し、 を使用する場合は値を保存できますWeakValueDictionary

補足: python2 では、.items()既にリストが返されます。

最終的には、「安全」が何を意味するかによって異なります。単純に反復が正しく進行することを意味する場合 (すべての要素に対して 1 回反復する)、次のようになります。

for k,v in list(d.items()):

辞書の反復は実際には によって実行されるlist(d.items())ため、リストを反復するだけなので安全です。

代わりに、反復中に - ループの副作用として要素が辞書から「消える」べきではないことを意味する場合はfor、ループの終わりまで強い参照を保持する必要があり、これにはリストを保存する必要がありますループを開始する前に変数に。

于 2012-09-14T17:55:51.713 に答える
0

ガベージ コレクタを無効にします。

import gc

gc.disable()
try:
    items = list(d.items())
finally:
    gc.enable()

次に、代わりに繰り返しitemsます。

于 2019-01-31T05:47:43.550 に答える