파이썬 세트가 삽입 순서를 유지하지 않는 이유는 무엇입니까?


12

dicts는 Python 3.7 이상에서 삽입 순서를 유지한다고 보장되지만 세트는 그렇지 않습니다.

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> d
{'a': 1, 'b': 2, 'c': 3}
>>> d['d'] = 4
>>> d
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> s = {'a', 'b', 'c'}
>>> s
{'b', 'a', 'c'}
>>> s.add('d')
>>> s
{'d', 'b', 'a', 'c'}

이 차이의 근거는 무엇입니까? 파이썬 팀이 dict 구현을 변경하여 동일한 세트로 적용되지 않은 것과 동일한 효율성 개선이 있습니까?

나는 순서대로 설정된 구현에 대한 포인터 나 딕트를 세트의 스탠드 인으로 사용하는 방법을 찾고 있지 않습니다. 파이썬 팀이 내장 세트가 dicts와 동시에 순서를 유지하지 않는 이유가 궁금합니다.


1
이것이 귀하의 질문에 대답합니까? 파이썬에는 순서가 있습니까?
Mihai Chelaru

1
아니요, 파이썬에는 주문 세트가 내장되어 있지 않다는 것을 알고 있습니다. 이제 dicts가 주문되었으므로 왜 그런지 궁금합니다.
Bart Robinson

4
사용 패턴이 다르기 때문에 사용 사례에 따라 최적화됩니다. CPython에서 집합이 null 값을 가진 dicts라는 일반적인 오해가 있습니다. 이는 완전히 잘못된 것입니다. 구현이 다릅니다. 질문이 닫히지 않으면 자세한 답변을 게시 할 수 있습니다.
wim

1
"사용 패턴이 다르기 때문에 사용 사례에 따라 최적화됩니다." 질문에 대한 좋은 대답은 이것에 대해 자세히 설명 할 것이라고 생각합니다. 문제는 두 가지 접근 방식이 해당 사용 사례에 최적 인 이유에 관한 것입니다.
Karl Knechtel

PyPy는 2.7 이후 dict와 동일한 순서를 사용합니다 set.
MisterMiyagi

답변:


10

세트와 dicts는 다양한 사용 사례에 최적화되어 있습니다. 세트의 주요 용도는 빠른 멤버쉽 테스트이며 주문과 무관합니다. dicts의 경우 조회 비용이 가장 중요한 작업이며 키가 존재할 가능성이 큽니다. 세트를 사용하면 요소의 존재 유무를 미리 알 수 없으므로 세트 구현은 발견 된 경우와 발견되지 않은 경우 모두에 대해 최적화해야합니다. 또한 공용체 및 교집합과 같은 일반적인 집합 작업에 대한 일부 최적화로 인해 성능 저하없이 집합 순서를 유지하기가 어렵습니다.

두 데이터 구조는 모두 해시 기반이지만 집합이 null 값을 가진 dict로 구현되는 것은 일반적인 오해입니다. 심지어 전에 CPython의 3.6 컴팩트 DICT 구현, 설정 및 DICT 구현은 이미 약간의 코드 재사용과 크게 달랐다. 예를 들어, dicts는 랜덤 프로빙을 사용하지만, 세트는 캐시 프로빙 성을 향상시키기 위해 선형 프로빙 및 개방 주소 지정을 조합하여 사용합니다. 초기 선형 프로브 ( CPython의 기본 9 단계 )는 일련의 인접 키 / 해시 쌍을 검사하여 해시 충돌 처리 비용을 줄여 성능을 향상시킵니다. 연속 메모리 액세스는 분산 프로브보다 저렴합니다.

그것은 컴팩트 DICT 유사하게 CPython과의 일련의 구현을 변경하려면 이론적으로하지만, 실제로는 단점이 있고, 주목할만한 핵심 개발자가 이러한 변경을 반대했다.

세트는 정렬되지 않은 상태로 유지됩니다. (왜? 사용 패턴이 다르며 구현 방식도 다릅니다.)

귀도 반 로섬

삽입 순서를 유지하기 위해 수정할 수없는 다른 알고리즘을 사용합니다. 주문 제작이 필요한 경우 세트 간 작업의 유연성과 최적화가 손실됩니다. 세트 수학은 비 순차 세트로 정의됩니다. 요컨대, 정해진 순서는 곧 나오지 않습니다.

레이몬드 헤 팅거

3.7에 대한 세트를 압축 할 것인지에 대한 자세한 설명과 결정된 이유에 대한 답변은 python-dev 메일 링리스트에서 찾을 수 있습니다.

요약하면 요점은 사용 패턴이 다르다는 것입니다 (** kwargs와 같은 삽입 순서는 유용합니다) 하지만 세트에는 적지 않음) 압축 세트에 대한 공간 절약은 중요하지 않습니다 (키 및 해시 배열 만 있기 때문입니다). 키, 해시 및 값과 달리 밀도를 높이고 집합에서 위에서 언급 한 선형 프로빙 최적화는 소형 구현과 호환되지 않습니다.

아래에서 가장 중요한 요점을 다루는 Raymond의 게시물을 재현하겠습니다.

Eric Snow는 2016 년 9 월 14 일 오후 3시 50 분에 다음과 같이 썼습니다.

그런 다음 세트와 동일하게 수행합니다.

내가 오해하지 않는 한 Raymond는 비슷한 설정을 변경하는 데 반대했습니다.

맞습니다. 사람들이 사나운 달리기 전에 주제에 대한 몇 가지 생각이 있습니다.

  • 간결한 전략의 경우, 공간 절약은 인덱스에 의해 소비되는 추가 공간과 키 / 값 / 해시 어레이의 초과 할당이 키 / 값 / 해시 어레이의 향상된 밀도에 의해 상쇄되는 것보다 큰 이익이었습니다. 그러나 세트의 경우 여전히 지수와 초과 할당이 필요하지만 3 개의 어레이 중 2 개만 치밀화하여 공간 비용 만 상쇄 할 수 있기 때문에 순은 훨씬 덜 유리합니다. 즉, 키, 값 및 해시를위한 공간을 낭비한 경우 압축이 더 의미가 있습니다. 이 세 가지 중 하나를 잃어 버리면 설득력이 없어집니다.

  • 세트의 사용 패턴은 dicts와 다릅니다. 전자는 조회수 나 조회수가 더 많습니다. 후자는 누락 된 키 조회가 적은 경향이 있습니다. 또한 세트 간 작업에 대한 일부 최적화로 인해 성능에 영향을주지 않고 세트 순서를 유지하기가 어렵습니다.

  • 세트 성능을 향상시키기위한 대체 경로를 추구했습니다. 공간을 많이 차지하지 않고 추가 간접 비용이 발생하는 압축 대신 선형 비용을 추가하여 충돌 비용을 줄이고 캐시 성능을 향상 시켰습니다. 이 개선 사항은 사전을 위해 권장 한 압축 방법과 호환되지 않습니다.

  • 현재 사전의 순서 부작용은 보장되지 않으므로 세트가 순서화되도록 주장하는 것은 시기상조입니다. 문서가 이미 OrderedSet ( https://code.activestate.com/recipes/576694/ ) 을 만들기위한 레시피에 링크되어 있지만 섭취량이 거의 0 인 것처럼 보입니다. 또한 Eric Snow가 빠른 OrderedDict를 제공했기 때문에 MutableSet 및 OrderedDict에서 OrderedSet을 작성하는 것이 그 어느 때보 다 쉬워졌지만 일반적인 세트 간 데이터 분석이 실제로는 아니기 때문에 실제로 관심을 보지 못했습니다. 주문이 필요하거나 걱정됩니다. 마찬가지로 빠른 회원 자격 테스트는 순서에 관계없이 사용됩니다.

  • 즉, PyPI에 대체 세트 구현을 추가 할 여지가 있다고 생각합니다. 특히, 전체 키 범위를 비교하여 세트-세트 작업을 가속화 할 수있는 주문 가능한 데이터에 대한 흥미로운 특수 사례가 있습니다 ( https://code.activestate.com/recipes/230113-implementation-of- 시작점에 대한 set-using-sorted-lists ). IIRC, PyPI에는 이미 세트 형 블룸 필터 및 뻐꾸기 해싱 코드가 있습니다.

  • 필자는 파이썬 코어에 주요 코드 블록을 수용하는 것이 흥미 롭다는 것을 이해하지만 그것이 확실하지 않다면 다른 데이터 유형을 더 많이 다시 작성하는 홍수에 열리지 않아야한다는 것을 이해합니다.

– 레이몬드 헤 팅거

에서 [파이썬 데브] 파이썬 3.6 DICT 소형되고 개인 버전을 가져옵니다; 키워드가 주문됩니다 ( 2016 년 9 월).


2

토론

귀하의 질문은 독창적이며 python-devs에 대해서는 이미 오래 전에 논의 되었습니다 . R. Hettinger 는 해당 스레드의 이론적 근거 목록을 공유했습니다 . 문제의 상태는이 상세한 답변 이 나온 직후 공개적으로 나타납니다. T. Peters의 .

요컨대, 삽입 순서를 유지하는 최신 dicts의 구현은 고유하며 세트에 적합하지 않은 것으로 간주됩니다. 특히 dicts는 파이썬을 실행하기 위해 모든 곳에서 사용됩니다 (예 : __dict__객체 네임 스페이스). 현대의 욕구의 주된 동기는 크기를 줄이고 파이썬을 전체적으로 메모리 효율적으로 만드는 것입니다. 대조적으로, 세트는 파이썬 코어 내의 dicts보다 덜 널리 퍼져서 그러한 리팩토링을 설득합니다. 현대 dict 구현에 대한 R. Hettinger의 이야기 를 참조하십시오 .


관점

파이썬에서 비 정렬 된 집합의 특성은 수학 집합 의 동작과 유사 합니다 . 주문은 보장되지 않습니다.

해당 수학적 개념은 순서가 없으며 순서 -R. Hettinger 와 같이 부과하는 것이 이상합니다 .

파이썬에서 어떤 종류의 순서가 세트에 도입 된 경우 ,이 동작은 완전히 분리 된 수학적 구조, 즉 순서 세트 (또는 Oset)를 준수합니다. Osets는 수학, 특히 조합론에서 별도의 롤을합니다. 벨의 변화 에서 Osets의 실제 적용이 관찰됩니다 .

비 순차 집합을 갖는 것은 가장 현대적인 유비쿼터스 데이터 구조와 일치하며, 가장 현대적인 수학, 즉 Set Theory 를 풀 수 있습니다. 나는 파이썬에서 비 순차 세트를 갖는 것이 좋습니다.

이 주제와 관련된 관련 게시물도 참조하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.