python3.7에서 파이썬 사전을 뒤집을 수없는 이유는 무엇입니까?


11

3.7부터 표준 파이썬 사전이 삽입 순서를 유지하도록 보장됩니다. (*)

d = {'b': 1, 'a': 2}
for k in d: 
    print(k)
# Prints always 'b' before 'a'.

즉, dict 키는 엄격한 순서로 유지됩니다. 원칙적으로 이것은 키를 뒤집을 수있게합니다. 그러나 다음 중 어느 것도 작동하지 않습니다.

# TypeError: 'dict' object is not reversible
for k in reversed(d): 
    print(k)

# TypeError: 'dict_keys' object is not reversible
for k in reversed(d.keys()): 
    print(k)

질문 : 이 행동의 원인은 무엇입니까? 받아쓰기를 뒤집을 수없는 이유는 무엇입니까? 앞으로이 동작을 변경할 계획이 있습니까?

해결 방법은 물론 작동합니다.

for k in reversed(list(d.keys())): 
    print(k)

(*) 사실, 이 글 에서 논의한 바와 같이, 일반적인 파이썬 3.6 설치의 경우 입니다.


업데이트 : python 3.8 dict로 시작하면 실제로 뒤집을 수 있습니다. 허용 된 답변은 Guido와이 핵심 결정을 이끌어 낸 다른 핵심 개발자 간의 토론을 나타냅니다. 간단히 말해, 구현 노력과 사용자의 실제 이점에 대해 언어 일관성을 평가했습니다.

답변:


5

로부터 문서 :

반전 됨 ( seq )

반대를 돌려 iterator줍니다. seq는 __reversed__()메소드가 있거나 시퀀스 프로토콜 ( 0부터 시작하는 정수 인수를 가진 __len__()메소드 및 메소드)을 지원 하는 오브젝트 여야합니다 __getitem__().

dict객체는 구현하지 않습니다 __reversed__. 후자의 두 가지 방법을 모두 구현합니다. 그러나 __getitem__0부터 시작하는 정수가 아닌 키를 인수로 사용합니다.

이유에 대해서는 이미 여기 에서 제안되고 논의 되었습니다 .

편집하다:

이 인용문은 Python-Dev 메일 링리스트 (스레드에 "Add __reversed__ 메소드", 25. 05. 18에 시작)에서 나 왔으며, "개념적"인수부터 시작하겠습니다. 첫 번째는 Antoine Pitrou입니다.

OrderedDict가 이미 reversed ()를 지원한다는 것은 가치가 없습니다. 논쟁은 두 가지 방법으로 진행될 수 있습니다.

  1. dict는 오늘날 OrderedDict와 유사하므로 reversed ()도 지원해야합니다.

  2. OrderedDict를 사용하여 주문에 관심이 있음을 명시 적으로 알릴 수 있습니다. dict에 추가 할 필요가 없습니다.

내 생각은 정규 dicts에 대한 보장 된 삽입 순서가 완전히 새로운 것이므로 개념이 정착하고 dicts에 대한 일상적인 생각의 일부가되는 데 시간이 걸릴 것입니다. 그런 일이 발생하면 유스 케이스가 나타나고 어느 시점에서 __reversed__가 추가되는 것이 불가피합니다. 구현은 간단 해 보이며 유한 한 컬렉션이 가역적 일 것이라고 기대하는 것은 개념적으로 큰 도약이 아닙니다.

Raymond Hettinger의 답변 :

dicts가 삽입 순서를 추적한다는 점을 감안하면 가장 최근에 삽입 한 것을 알고 싶을 것입니다 (즉, 작업 dict에서 가장 최근에 추가 된 작업을 반복하는 것). 다른 가능한 사용 사례는 우리가 Unix tail 명령을 사용하는 방법과 일치 할 것입니다.

이러한 유스 케이스가 발생하면 __reversed__가 이미 지원되어 사람들이 popitem () 호출과 다시 삽입을 사용하여 추악한 해결 방법을 구현하려는 유혹을받지 않을 수 있습니다.

메일 링리스트 표현 된 주요 관심사는 적어도 일부 구현에서 너무 많은 부풀림을 추가하거나 메모리 효율성 (단일로 연결된리스트 대신 이중 링크 된리스트를 가짐)을 감소시킬 것이라는 점이었습니다. ) :

"주문했다"는 것이 "가역적"이라는 의미는 아닙니다. 예를 들어, 단일 연결 목록은 순서가 정해져 있지만 되돌릴 수는 없습니다.

CPython의 구현이 효율적으로 제공 할 수 있지만 __reverse__, 추가 __reverse__수단이 모든 파이썬 구현을 제공 할 것으로 기대된다. 예를 들어, 일부 Python 구현은 hashmap + single linked list로 dict를 구현할 수 있습니다. 경우 __reverse__추가, 그것은 더 이상 수 없습니다.

메일 링리스트로 돌아가서 마지막 두 가지 메시지가 있습니다 (둘 다 08.06.2018에 게시 됨). 첫 번째는 Michael Selik입니다.

v3.8에 포함 된 합의가 +1이라고 말하는 것이 맞습니까?

스레드의 마지막 요점은 INADA Naoki가 다양한 구현을 연구하고 3.8에이 기능을 포함시키는 것이 좋다고 결정했습니다. 내가 이해하는 것처럼 Guido는 MicroPython의 v3.7 구현을 기다리는 INADA의 조언에 동의했습니다. INADA가 마음을 바꿨 기 때문에 모든 것이 유리한 것 같아요?

귀도 반 로섬의 메시지 결론 :

그거 나에게 들린다. 그런 다음 두 가지 버전이있을 것입니다.

  • 3.6 순서 보존은 CPython에서 구현되었지만 언어 사양에서는 구현되었습니다.

  • 3.7 언어 사양에 추가 된 곳

다른 답변과 의견에서 언급했듯이 reversed()버전 3.8 (14.10.2018) 이후의 dicts 및 dictviews 모두 지원됩니다.


5
두 번째 인용문은 해당 스레드의 바이어스 선택과 같습니다. 컨센서스는 기능이 3.8에 추가 될 것으로 보인다. 또한이 파이썬 3.7 이전에 단순히 정상에 더 주문 없었다 dict그래서 객체 (적어도 언어에서 보장하지 않음) reversed또한 아무 의미하지
FlyingTeller

나는 싸움에 개가 없다. 나는 그의 첫 반응을 인용했다. 그러나 당신 말이 맞아요. 잘 인용했습니다. 나는 인용문을 제거했습니다.
gst

1
감사. python-dev의 토론 스레드가 공개되었습니다. 실제로이 기능은 이미 며칠 전에 출시 된 python 3.8에서 이미 구현되었습니다 (2019 년 10 월 14 일).
normanius


문서 인용문은 도움이되지 않습니다. 다음 질문 "왜 dict 유형이 구현되지 __reversed__않습니까?" python-dev 링크에는 유용한 내용이 있지만 관련 부분은 답변으로 직접 재현해야합니다 (외부 사이트 링크는 썩는 경향이 있으므로).
wim


1

Python 3.8 업데이트

딕 트뷰 및 dictviews는 이제 reversed ()를 사용하여 역 삽입 순서로 반복 가능합니다.

>>> dict = {1: "1", 2: "2", 3: "3"}
>>> reversed(dict)
<dict_reversekeyiterator object at 0x7f72ca795130>

이 답변은 아직 다른 답변, 의견 또는 질문 자체에 포함되지 않은 새로운 내용을 제공합니까?
normanius

@normanius 릴 비주얼 코드 샘플이 있으며 빠른 브라우저에 도움이 될 것입니다
jamylak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.