web-dev-qa-db-ja.com

辞書はPython 3.6以降で注文されていますか?

辞書は、以前の形とは異なり、Python 3.6(少なくともCPython実装の下)で並べられています。これは大幅な変更のようですが、 ドキュメント の短い段落にすぎません。これは言語機能ではなくCPython実装の詳細として記述されていますが、これが将来標準になるかもしれないことも暗示しています。

要素の順序を維持しながら、新しい辞書の実装は古い辞書の実装よりも優れていますか?

これがドキュメントからのテキストです。

dict()は「コンパクト」表現 PyPyによって開発された を使います。新しいdict()のメモリ使用量は、Python 3.5と比較して20%から25%小さくなっています。これによって PEP 468 (関数内の** kwargsの順序を保持する)が実装されます。この新しい実装の順序保持の側面は実装の詳細と考えられており、信頼するべきではありません(これは将来変更される可能性がありますが、言語仕様を変更する前にいくつかのリリースでこの新しい辞書実装を言語で使用することをお勧めします)現在および将来のすべてのPython実装に対して順序を維持するセマンティクスを強制すること;これは、ランダムな繰り返し順序がまだ有効である古いバージョンの言語、たとえばPython 3.5との後方互換性を維持するのにも役立ちます。 (INADA Naokiによる issue 27350 。Idea Raymond Hettingerによる提案 。の寄稿)

2017年12月の更新:挿入順序を保持するdictsはPython 3.7では 保証 です

320
Chris_Rands

辞書はPython 3.6 +?で注文されていますか

挿入注文 [1] 。 Python 3.6の時点で、PythonのCPython実装では、辞書は挿入されたアイテムの順序を記憶しますこれは、Python 3.6の実装の詳細と見なされます。 Pythonのその他の実装(およびその他の順序付けられた動作)でguaranteedの挿入順序が必要な場合は、OrderedDictname__を使用する必要があります。 [1] )。

Python 3.7 以降、これは実装の詳細ではなく、代わりに言語機能になります。 GvRによるpython-devメッセージから

そうしてください。 「管轄は広告掲載順序を維持する」が決定です。ありがとう!

これは単純に依存できることを意味します。 Python 3.7の実装に準拠する場合は、Pythonの他の実装でも挿入順序辞書を提供する必要があります。


Python 3.6辞書実装のパフォーマンスはどのように向上しますか[2] 要素の順序を維持しながら古いものよりも?

基本的に、2つの配列を保持することにより

  • 最初の配列 dk_entries は、辞書のエントリ( タイプPyDictKeyEntryname __ )を、挿入された順序で保持します。これは、新しいアイテムが常に最後に挿入される追加のみの配列であるため、順序が維持されます(挿入順序)。

  • 2番目の dk_indices は、dk_entries配列のインデックス(つまり、dk_entriesの対応するエントリの位置を示す値)を保持します。この配列はハッシュテーブルとして機能します。キーがハッシュされると、dk_indicesに格納されているインデックスの1つにつながり、dk_entriesにインデックスを付けることで対応するエントリが取得されます。インデックスのみが保持されるため、この配列のタイプは辞書の全体サイズに依存します(タイプ int8_t1 byte)から int32_t / int64_t4/8 bytes)on 32/64 bit builds)

以前の実装では、タイプPyDictKeyEntryname__およびサイズdk_sizeのスパース配列を割り当てる必要がありました。残念なことに、その配列は2/3 * dk_size fullを超えることは許可されていないため、多くの空のスペースが生じました パフォーマンス上の理由で 。 (および空のスペースstillのサイズはPyDictKeyEntryname__でした!)。

requiredエントリ(挿入されたもの)のみが保存され、intX_t型のスパース配列(dictサイズに応じてXname__)2/3 * dk_sizesフルが保持されるため、これは現在ではありません。空のスペースがタイプPyDictKeyEntryname__からintX_tに変更されました。

したがって、PyDictKeyEntryname__型のスパース配列を作成すると、intname__sを格納するためのスパース配列よりも多くのメモリが必要になります。

興味があれば、この機能に関する完全な会話 Python-Devで を見ることができます。


Raymond Hettingerによるオリジナルの提案 では、使用されたデータ構造の視覚化を見ることができ、それがアイデアの要点を捉えています。

たとえば、辞書は次のとおりです。

d = {'timmy': 'red', 'barry': 'green', 'guido': 'blue'}

現在、次のように保存されています。

entries = [['--', '--', '--'],
           [-8522787127447073495, 'barry', 'green'],
           ['--', '--', '--'],
           ['--', '--', '--'],
           ['--', '--', '--'],
           [-9092791511155847987, 'timmy', 'red'],
           ['--', '--', '--'],
           [-6480567542315338377, 'guido', 'blue']]

代わりに、データは次のように編成する必要があります。

indices =  [None, 1, None, None, None, 0, None, 2]
entries =  [[-9092791511155847987, 'timmy', 'red'],
            [-8522787127447073495, 'barry', 'green'],
            [-6480567542315338377, 'guido', 'blue']]

視覚的にわかるように、元の提案では、衝突を減らしてルックアップを高速化するために、多くのスペースが本質的に空になっています。新しいアプローチでは、インデックスでスパースネスを実際に必要な場所に移動することで、必要なメモリを削減します。


[1]:OrderedDictの存在により、「ordered」はdictname__オブジェクトが提供しない動作を示唆するため、「ordered」ではなく「ordered」と言います。 OrderedDictsはリバーシブルであり、順序に敏感なメソッドを提供し、主に順序に敏感な等価テスト(==!=)を提供します。 dictname__sは現在、これらの動作/メソッドを提供していません。


[2]:新しいディクショナリ実装は、よりコンパクトに設計されることにより、メモリの賢さにより優れたパフォーマンスを発揮します。それがここでの主な利点です。スピードに関しては、違いはそれほど劇的ではなく、新しい辞書がわずかな回帰( key-lookups、例えば )を導入する場所がありますが、他の(反復とサイズ変更が頭に浮かぶ)パフォーマンスの向上があります存在する必要があります。

全体的に、特に実際の状況での辞書のパフォーマンスは、導入されたコンパクトさにより向上します。

387

以下は最初の最初の質問に答えるものです。

Python 3.6ではdictOrderedDictのどちらを使うべきですか?

私はドキュメンテーションからのこの文はあなたの質問に答えるのに実際に十分であると思います

この新しい実装の順序保持の側面は実装の詳細と見なされるため、信頼するべきではありません。

dictは明示的に順序付けされたコレクションであることを意図していません。そのため、一貫性を保ち、新しい実装の副作用に頼らないのであれば、OrderedDictを固執する必要があります。

あなたのコードを将来の証拠にする:)

これについては議論があります ここ

編集:Python 3.7は機能としてこれを維持します - 参照

61
Maresh

更新:Guido van Rossum メーリングリストで発表された Python 3.7以降、すべてのPython実装でのdictsは挿入順序を守らなければならないことを発表しました。

18
fjsj

上記の議論に追加したかったのですが、コメントする評判はありません。

Python 3.8はまだ完全にはリリースされていませんが、辞書にreversed()関数を含めることもできます(OrderedDictとは別の違いがあります)。

Dictおよびdictviewは、reversed()を使用して、逆の挿入順序で反復可能になりました。 (bpo-33462のRémiLapeyreによる寄稿。) python 3.8の新機能をご覧ください

等号演算子やOrderedDictのその他の機能については言及していないので、まだ完全に同じではありません。

1
rkengler