OrderedDict
バージョン 2.7 以降のある時点で修正されたバグを追跡したようです。実際にリリースされたバージョンに含まれていない場合は、無視してかまいません。しかし、それ以外の場合は、回避策が必要です。
monkeypatching の代わりに、ドキュメントにリンクされているPython 2.4 以降で実行される同等の OrderedDict レシピをcollections.OrderedDict
代わりに使用することをお勧めします(これには余分な はありません)。少なくとも、誰かがやって来て、「これを 2.6 で実行する必要があります。移植するのにどれだけの作業が必要ですか」と言うと、答えは「少し少ない」でしょう…</p>
collections.OrderedDict
__del__
しかし、さらに2つのポイント:
サイクルを回避するためにすべてを書き直すことは、膨大な労力を要します。
辞書にサイクルがあるという事実は、何か間違ったことをしている危険信号です (通常、キャッシュまたはバックポインターに強い参照を使用しています)。これは、他のメモリの問題につながる可能性があり、おそらく他のメモリの問題につながる可能性があります。バグ。ですから、その努力はいずれ必要になるかもしれません。
何を達成しようとしているのかをまだ説明していません。「決定論的」なことは単なる赤いニシンであると思われるため(特にdict
s は実際には決定論的であるため)、最良の解決策はs/OrderedDict/dict/g
.
ただし、決定論が必要な場合は、サイクルコレクターに依存することはできません。これは決定論的ではないためです。つまり、ファイナライザーの順序付けなどがすべて非決定論的になります。また、メモリ使用量が非決定論的であることも意味します。100% ではなく、99.999% の確率で目的のメモリ範囲内にとどまるプログラムになる可能性があります。それらの境界が非常に重要である場合、毎回失敗するよりも悪い可能性があります。
一方、辞書の反復順序は指定されていませんが、実際には、CPython と PyPy は、値またはキーの ID (メモリの場所) ではなく、Jython と IronPython が行うこと (動作が異なる Java または .NET コレクションを使用している可能性があります (私はテストしていません)。(そのようなものに基づいてハッシュ テーブルを効率的に反復するにはどうすればよいでしょうか?) id
forを使用するオブジェクトでテストして混乱したかもしれませんhash
が、ほとんどのオブジェクトは値に基づいてハッシュします。
たとえば、次の簡単なプログラムを見てみましょう。
d={}
d[0] = 0
d[1] = 1
d[2] = 2
for k in d:
print(k, d[k], id(k), id(d[k]), hash(k))
CPython 2.7、CPython 3.2、および PyPy 1.9 で繰り返し実行すると、キーは常に 0、1、2 の順序で反復されます。id
列も毎回同じになる場合があります (プラットフォームによって異なります)。さまざまな方法でそれを修正します — 別の順序で挿入する、値の順序を逆にする、int の代わりに文字列値を使用する、値を変数に割り当ててから、リテラルの代わりにそれらの変数を挿入するなど。列のすべての可能な順序を取得できますがid
、キーは毎回同じ順序で反復されます。
反復の順序は予測できません。予測hash(k)
するには、Python からアクセスできない情報に依存するバケット インデックスに変換する関数が必要だからです。ただの. hash(k) % self._table_size
_ _table_size
(これは、挿入と削除のシーケンスの複雑な関数であり、原則として計算できますが、実際に試すのはばかげています。)
しかし、それは決定論的です。毎回同じ順序で同じキーを挿入および削除すると、反復順序は毎回同じになります。