2013-02-19 2 views
27

최근에 파이썬 2.7에서 파이썬 3.3으로 바뀌 었습니다. 파이썬 2에서 사전 키의 순서는 임의적이지만 일관성이있는 것처럼 보입니다. 파이썬 3에서는 예를 들어서 얻은 사전의 키를 정렬합니다. vars()이 비 결정적으로 나타납니다.왜 사전 순서가 비 결정적입니까?

나는 실행하는 경우 : 모두 파이썬 2.7과 파이썬 3.3에서

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

, 다음 :

  • 파이썬 2.7은 지속적으로 파이썬 3.3으로 나에게

    ['__dict__', '__module__', '__weakref__', '__doc__'] 
    
  • 을 제공, I 임의 순서를 얻을 수 있습니다. 예 :

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

이 비 결정론은 어디서 비롯된 것입니까? 그리고 왜

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

과 같이 항상

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

을 제공, 실행 사이의 일치 ...는 ...?

답변

33

업데이트 : 파이썬 3.6 dict에서 삽입 순서를 보존하는 new implementation있다. 그러나 이는 구현 세부 사항이므로 의존해서는 안됩니다.


파이썬 3.3 enabled by default을했다 2012에서 security fix의 결과이다 ("보안 개선"아래로 스크롤). 발표에서

:

해시 무작위은 dicts의 반복 순서를 발생시키고 예측할 을하고 파이썬이 실행에 걸쳐 다르게 설정합니다. 파이썬은 dict 또는 set에서 키의 반복 순서를 보장하지 않았으므로 응용 프로그램에는 절대로 을 사용하지 않는 것이 좋습니다. 역사적으로, dict 반복 명령은 릴리스에서 매우 자주 변경되지 않았으며, Python의 연속 실행간에 항상 일관되게 유지되었습니다. 따라서 일부 기존 응용 프로그램은 dict 또는 set ordering에 의존 할 수 있습니다. 신뢰할 수없는 입력을 허용하지 않는 많은 Python 응용 프로그램이이 공격에 취약하지 않기 때문에 여기에 언급 된 안정적인 Python 릴리스 에서 해시 임의 화는 기본적으로 사용되지 않습니다.

위에서 언급했듯이, 마지막으로 대문자로 된 비트는 더 이상 파이썬 3.3에서 사실이 아닙니다.

참고 :object.__hash__() documentation ("참고"추가 기사).

절대적으로 필요한 경우 환경 변수를 0으로 설정하여이 동작의 영향을받는 Python 버전에서 해시 임의 화를 비활성화 할 수 있습니다.


귀하의 반례 :

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

... 하지 사실 다른 순서화의 수는 제한되어 있지만, 항상, 파이썬 3.3에서 같은 결과를 제공에 due to 해시 충돌 처리 방법을 수행합니다

$ 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'] 

이 답변의 시작 부분에서 언급했듯이 더 이상 파이썬 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 –

관련 문제