2013-02-19 6 views
27

私は最近Python 2.7からPython 3.3に切り替えました。そして、Python 2では辞書キーの順序は任意ですが一貫していたようですが、Python 3では、例えば辞書で取得された辞書のキーの順序があります。 vars()が非確定的に見えます。辞書の順序付けが非決定論的なのはなぜですか?

class Test(object): pass 
parameters = vars(Test) 
print(list(parameters.keys())) 

のPython 2.7とPython 3.3の両方で、次のようになります:

  • のPython 2.7が一貫してくれPythonの3.3で

    ['__dict__', '__module__', '__weakref__', '__doc__'] 
    
  • を与え、私は私が実行している場合は

    任意の順序を得ることができます。たとえば、

    ['__weakref__', '__module__', '__qualname__', '__doc__', '__dict__'] 
    ['__doc__', '__dict__', '__qualname__', '__module__', '__weakref__'] 
    ['__dict__', '__module__', '__qualname__', '__weakref__', '__doc__'] 
    ['__weakref__', '__doc__', '__qualname__', '__dict__', '__module__'] 
    

この非決定論はどこから来たのですか?そして、なぜいつも

['3', '2', '1', '0', '7', '6', '5', '4', '9', '8'] 

を与えて実行する、との一貫性の

list({str(i): i for i in range(10)}.keys()) 

のようなものは... ...ですか?

答えて

33

更新:Pythonの3.6dictはオーダーを保持new implementationを有しています。しかし、これは実装の詳細なので、依存するべきではありません。


これは、Python 3.3でenabled by default( "セキュリティの強化" にスクロールダウン)であった2012年からsecurity fix、の結果です。発表から

ハッシュのランダム化は、dictsの繰り返し順序を引き起こし、 予測不可能とPythonの実行を横切って異なることが設定されます。 Pythonは、dictまたはset内のキーの反復順序を 保証していないので、アプリケーションは決して に依存することをお勧めします。歴史的には、辞書の反復順序は、 のリリースで頻繁に変更されておらず、 Pythonの連続した実行の間は常に一貫していました。したがって、いくつかの既存のアプリケーションは、dictまたはset orderingに依存している可能性があります。 信頼できない入力を受け付けない多くのPythonアプリケーションがこの攻撃に対して脆弱ではないという事実があるため、安定したPythonリリース では、HASHのランダム化はデフォルトでは無効になっています。

上記のように、大文字の最後のビットは、Python 3.3ではもはや真ではありません。

も参照してください。object.__hash__() documentation(「ノート」のサイドバー)。

絶対に必要な場合は、環境変数を0に設定して、この動作の影響を受けるバージョンのPythonでハッシュランダム化を無効にすることができます。


あなたの反例:

list({str(i): i for i in range(10)}.keys()) 

...異なる順序の数がハッシュ衝突が処理されるdue to限定的ではあるが実際にはないは常に、Pythonの3.3で同じ結果が得られない:

$ for x in {0..999} 
> do 
> python3.3 -c "print(list({str(i): i for i in range(10)}.keys()))" 
> done | sort | uniq -c 
    61 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 
    73 ['1', '0', '3', '2', '5', '4', '7', '6', '9', '8'] 
    62 ['2', '3', '0', '1', '6', '7', '4', '5', '8', '9'] 
    59 ['3', '2', '1', '0', '7', '6', '5', '4', '9', '8'] 
    58 ['4', '5', '6', '7', '0', '1', '2', '3', '8', '9'] 
    55 ['5', '4', '7', '6', '1', '0', '3', '2', '9', '8'] 
    62 ['6', '7', '4', '5', '2', '3', '0', '1', '8', '9'] 
    63 ['7', '6', '5', '4', '3', '2', '1', '0', '9', '8'] 
    60 ['8', '9', '0', '1', '2', '3', '4', '5', '6', '7'] 
    66 ['8', '9', '2', '3', '0', '1', '6', '7', '4', '5'] 
    65 ['8', '9', '4', '5', '6', '7', '0', '1', '2', '3'] 
    53 ['8', '9', '6', '7', '4', '5', '2', '3', '0', '1'] 
    62 ['9', '8', '1', '0', '3', '2', '5', '4', '7', '6'] 
    52 ['9', '8', '3', '2', '1', '0', '7', '6', '5', '4'] 
    73 ['9', '8', '5', '4', '7', '6', '1', '0', '3', '2'] 
    76 ['9', '8', '7', '6', '5', '4', '3', '2', '1', '0'] 

この回答の冒頭で述べたように、これはPython 3.6ではなくなりました。

$ for x in {0..999} 
> do 
> python3.6 -c "print(list({str(i): i for i in range(10)}.keys()))" 
> done | sort | uniq -c 
    1000 ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'] 
+1

なぜ、これは '{str(i):i for i in range(10)} 'には当てはまりませんか? – Anaphory

+0

このランダム化をどのように無効にするのですか? – nmz787

+2

@ nmz787 https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHASHSEED –

関連する問題