このビデオを見る必要があります(これは CPython 1固有の辞書に関するものですが、セットにも当てはまると思います)。
基本的に、Python は要素をハッシュし、最後の N ビット (N はセットのサイズによって決まります) を取得し、それらのビットを配列インデックスとして使用して、オブジェクトをメモリに配置します。オブジェクトは、メモリに存在する順序で生成されます。もちろん、ハッシュ間の衝突を解決する必要がある場合、状況はもう少し複雑になりますが、それが要点です。
また、それらが印刷される順序は、それらを配置した順序によって決定されることに注意してください (衝突のため)。そのため、 に渡すリストの順序を変更するとset_2
、キーの衝突がある場合に別の順序で出力される可能性があります。
例えば:
list1 = [8,16,24]
set(list1) #set([8, 16, 24])
list2 = [24,16,8]
set(list2) #set([24, 16, 8])
これらのセットで順序が保持されるという事実は「偶然」であり、衝突の解決に関係していることに注意してください(これについては何も知りません)。hash(8)
ポイントは、 、、 の最後の 3 ビットが同じであることですhash(16)
。hash(24)
それらは同じであるため、衝突の解決が引き継ぎ、要素を最初の (最良の) 選択ではなく「バックアップ」メモリの場所に配置し8
ます16
。シート"。
1
、 、を使用して例を繰り返す2
と3
、入力リスト内の順序に関係なく、一貫した順序が得られます。
list1 = [1,2,3]
set(list1) # set([1, 2, 3])
list2 = [3,2,1]
set(list2) # set([1, 2, 3])
の最後の 3 ビット以降hash(1)
、hash(2)
およびhash(3)
は一意です。
1注ここで説明する実装は、CPythondict
およびset
. 一般的な説明は、3.6 までの CPython のすべての最新バージョンに有効だと思います。ただし、CPython3.6 以降では、 の反復の挿入順序を実際に保持する追加の実装の詳細がありますdict
。このプロパティはset
まだないようです。データ構造は、pypy の人々 (CPython の人々よりも前にこれを使い始めた)によるこのブログ投稿で説明されています。元のアイデア (少なくとも python エコシステム用)は python-dev メーリング リスト にアーカイブされています。