[python] Python 3.6 이상에서 사전이 주문됩니까?

사전은 이전 화신과 달리 Python 3.6 (최소한 CPython 구현)에서 주문됩니다. 이것은 실질적인 변화처럼 보이지만 문서 의 짧은 단락 일뿐 입니다. 언어 기능이 아닌 CPython 구현 세부 사항으로 설명되지만 앞으로 이것이 표준이 될 수 있음을 암시합니다.

요소 사전을 유지하면서 새로운 사전 구현이 이전 사전보다 어떻게 더 잘 수행됩니까?

다음은 설명서의 텍스트입니다.

dict()이제 PyPy가 개척 한 “소형”표현을 사용합니다 . 새로운 dict ()의 메모리 사용량은 Python 3.5에 비해 20 %에서 25 % 사이입니다. PEP 468 (함수에서 ** kwargs의 순서 유지)이 구현됩니다. 이 새로운 구현의 순서 유지 측면은 구현 세부 사항으로 간주되며 의존해서는 안됩니다 (향후 변경 될 수 있지만 언어 사양을 변경하기 전에 몇 가지 릴리스에 대해 언어 로이 새로운 dict 구현을 갖는 것이 바람직합니다 현재와 ​​미래의 모든 파이썬 구현에 대한 순서 유지 의미론을 강제하기 위해; 이것은 또한 임의의 반복 순서가 여전히 유효한 이전 버전의 언어와의 하위 호환성을 유지하는 데 도움이됩니다 (예 : Python 3.5). (INADA Naoki가 제공 한문제 27350 . Raymond Hettinger가 처음 제안한 아이디어 .)

2017 년 12 월 업데이트 : Python 3.7에 대한 게재 dict신청서 유지 보장



답변

Python 3.6 이상에서 사전이 주문됩니까?

그것들은 삽입 순서가되어있다 [1] . Python 3.6부터 CPython Python 구현에서 사전 은 삽입 된 항목의 순서를 기억합니다 . 이것은 Python 3.6에서 구현 세부 사항으로 간주됩니다 . 다른 파이썬 구현 OrderedDict에서 보장 되는 삽입 순서 (및 기타 정렬 된 동작 [1] ) 를 원할 경우 사용해야 합니다 .

Python 3.7부터는 더 이상 구현 세부 사항이 아니며 언어 기능이됩니다. GvR의 python-dev 메시지에서 :

그렇게 만들어. “사전 삽입 순서 유지”는 판결입니다. 감사!

이것은 단순히 당신이 그것에 의존 할 수 있다는 것을 의미 합니다 . 파이썬의 다른 구현은 파이썬 3.7의 적합한 구현이 되려면 삽입 순서 사전을 제공해야합니다.


어떻게 파이썬 않는 3.6사전 구현은 더 잘 수행 [2] 이전보다가 그대로 유지하면서 요소 순서를?

본질적으로 두 개의 배열유지함으로써 .

  • 첫 번째 배열 인 에는 사전에 대한 dk_entries항목 ( 유형PyDictKeyEntry )을 삽입 된 순서대로 보유합니다 . 보존 순서는 새 항목이 항상 끝에 삽입되는 추가 전용 배열 (삽입 순서)로 이루어집니다.

  • 두 번째 dk_indicesdk_entries배열 의 인덱스 (즉,에서 해당 항목의 위치를 ​​나타내는 값 dk_entries)를 보유합니다. 이 배열은 해시 테이블 역할을합니다. 키가 해시되면 키가 저장된 인덱스 중 하나로 연결되고 dk_indices해당 항목은 색인화하여 가져옵니다 dk_entries. 인덱스 만이 유지되므로, 이러한 배열의 형태가 사전의 전체 크기 (레인 징의 타입에 따라 int8_t( 1바이트)로 int32_t/ int64_t( 4/ 8바이트)에 32/ 64비트 빌드)

이전 구현에서는 유형 PyDictKeyEntry과 크기 의 희소 배열을 dk_size할당해야했습니다. 불행히도, 성능상의 이유로 어레이가 2/3 * dk_size가득 차는 것을 허용하지 않았기 때문에 빈 공간이 많이 생겼습니다 . (그리고 빈 공간에는 여전히 크기 가 있습니다!).PyDictKeyEntry

단지 때문에 지금 그렇지 않다 필요한 항목의 입력은 희소 배열 (삽입 된 것)에 저장된다 intX_t( X딕셔너리 크기에 따라) 2/3 * dk_size의 전체 유지된다. 빈 공간이 유형에서 PyDictKeyEntry로 변경되었습니다 intX_t.

따라서, 희소 한 유형의 배열을 생성하는 PyDictKeyEntry것은 ints 를 저장하기위한 희소 배열보다 훨씬 더 많은 메모리를 요구 합니다.

관심이 있다면이 기능에 관한 Python-Dev 의 전체 대화 볼 수 있습니다 .


Raymond Hettinger의 원래 제안에서 , 사용 된 데이터 구조의 시각화를 통해 아이디어의 요점을 파악할 수 있습니다.

예를 들어 사전은 다음과 같습니다.

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

현재 [keyhash, key, value]로 저장됩니다 :

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”는 dict개체 가 제공하지 않는 추가 동작을 나타 내기 때문에 “inserted ordered” 가 아니라 “ordered” 가 아닙니다 . OrderedDict는 가역적이며 순서에 민감한 방법을 제공하며 주로 순서에 민감한 등식 테스트 ( ==, !=)를 제공합니다. dict현재 이러한 행동 / 방법을 제공하지 않습니다.



[2] : 새로운 딕셔너리 구현은보다 간결하게 설계되어보다 나은 메모리 성능을 제공합니다 . 이것이 주요 이점입니다. 현명하게도, 그 차이는 그다지 급격하지는 않습니다. 새로운 dict이 약간의 회귀 ( : 키 조회)를 유발할 수있는 반면, 다른 경우 (반복 및 크기 조정이 떠오를 경우)에는 성능 향상이 있어야합니다.


전반적으로, 특히 실제 상황에서 사전의 성능은 도입 된 소형화로 인해 향상됩니다.


답변

아래는 첫 번째 원래 질문에 대한 답변입니다.

나는 사용해야 dict또는 OrderedDict파이썬 3.6?

나는 문서 의이 문장이 실제로 귀하의 질문에 대답하기에 충분하다고 생각합니다

이 새로운 구현의 순서 유지 측면은 구현 세부 사항으로 간주되며 이에 의존해서는 안됩니다.

dict은 명시 적으로 순서가 지정된 컬렉션을 의미하지 않으므로 일관성을 유지하고 새로운 구현의 부작용에 의존하지 않으려면를 사용해야합니다 OrderedDict.

코드를 미래의 증거로 만드십시오 🙂

여기에 대한 논쟁이 있습니다 .

편집 : 파이썬 3.7는 기능으로이 유지됩니다 참조


답변

업데이트 : Guido van Rossum 은 메일 링리스트dict 에서 모든 Python 구현에서 Python 3.7부터 삽입 순서를 유지해야 한다고 발표했습니다 .


답변

위의 토론에 추가하고 싶었지만 언급 할만한 평판이 없습니다.

Python 3.8은 아직 출시되지 않았지만 reversed()사전에 대한 기능 도 포함합니다 (와 다른 차이점 제거) OrderedDict.

딕 트뷰와 dictviews는 이제 reversed ()를 사용하여 역 삽입 순서로 반복 가능합니다. (pyo 33462의 Rémi Lapeyre 제공)
Python 3.8의 새로운 기능보기

평등 연산자 또는 다른 기능에 대한 언급이 OrderedDict없으므로 완전히 동일하지 않습니다.


답변