사전은 이전 화신과 달리 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_indices
는dk_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
것은 int
s 를 저장하기위한 희소 배열보다 훨씬 더 많은 메모리를 요구 합니다.
관심이 있다면이 기능에 관한 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
없으므로 완전히 동일하지 않습니다.