2014-09-25 2 views
3

은 python3에서 이것은 단지python2에서 정의 순서를 사용할 수없는 이유는 무엇입니까?

>>> from enum import Enum 
>>> class Animal(Enum): 
...  cat = [0] 
...  dog = {1} 

작동하지만 메타 클래스 기지 값에 분류 호출하려고 할 때 처리되지 않은 예외가 있기 때문에 파이썬 v2.7.6에 그것은 TypeError를 발생시킵니다.

우리는이 같은 문제를 해결할 수 있습니다

>>> class Animal(Enum): 
...  __order__ = 'cat dog' 
...  cat = [0] 
...  dog = {1} 

내 질문을 왜 정의 순서가 python2에서 사용할 수 없습니다? 나는 그것이 왜 python2 버전이 작동하지 않는지 추측하고 있는데, 내가 틀렸다면 나를 바로 잡는다.

우리는이 같은 열거를 한 경우 : 안전하고 잘 정의 된

>>> class Animal(Enum): 
...  cat = {0, 1} 
...  dog = {1, 2} 
...  fish = {2, 0} 

순서가됩니까? 아니면 dict 또는 set 반복처럼 신뢰할 수 없습니까?


편집 : 메타 클래스는 __prepare__ 후크와와 대안 공간 구현을 지정할 수 preparing the class namespace : 역 추적

In [1]: from enum import Enum 

In [2]: class Animal(Enum): 
    dog = [0] 
    cat = {1} 
    ...:  
--------------------------------------------------------------------------- 
TypeError         Traceback (most recent call last) 
<ipython-input-2-d14b1041d5bc> in <module>() 
----> 1 class Animal(Enum): 
     2  dog = [0] 
     3  cat = {1} 
     4 

/usr/local/lib/python2.7/dist-packages/enum/__init__.pyc in __new__(metacls, cls, bases, classdict) 
    164   if __order__ is None: 
    165    if pyver < 3.0: 
--> 166     __order__ = [name for (name, value) in sorted(members.items(), key=lambda item: item[1])] 
    167    else: 
    168     __order__ = classdict._member_names 

TypeError: Error when calling the metaclass bases 
    can only compare to a set 
+0

파이썬 2에서 사용하는'enum' 구현은 무엇입니까? ['enum34' 백 포트 패키지 (https://pypi.python.org/pypi/enum34/)는 첫 번째 예제에서'TypeError'를 발생시키지 않습니다. 여기에 뭔가 빠졌습니까? –

+0

정확하게 pip freeze에 따라 enum34 백 포트, 버전'enum34 == 1.0 '입니다. 그리고 네, 파이썬 2.7.6에서 예외를 발생시키고 있습니다, 당신이 말하는 것이 아닙니다! – wim

+0

아마도 다른 구현 인 Martijn을 사용하고 있습니다. – wim

답변

6

열거 새로운 메타 클래스 기능을 사용한다와. 이것은 파이썬 2에서는 사용할 수 없습니다.

__prepare__ 사용자 지정 매핑 개체를 반환하면 클래스 본문의 정의 순서를 캡처 할 수 있습니다. _EnumDict implementationEnumMeta.__prepare__ definition을 참조하십시오. _member_names 특성은 목록이고 순서가 지정된 구조이며 Enum 하위 클래스의 이름은 정의 된대로 추가됩니다.

Python 2에서는 정의 순서를 유지하지 않는 클래스 본문에 대해 보통 dict 네임 스페이스가 사용되지 않습니다. 이와 같이 마지막 예에서 속성 순서는 사용 된 매핑 객체의 구현 세부 사항을 따릅니다. __order__ 속성이 없으면 Python 2 enum34은 값순으로 정렬하고 Python 2에서는 항목에 실제로 정의 된 순서가없는 경우 순서가 임의적이라는 것을 의미합니다. 세트의 순서가 정해지지 않은 이유는 다음과 같습니다.

>>> {0, 1} < {1, 2} 
False 
>>> {0, 1} > {1, 2} 
False 

원래 클래스 네임 스페이스 순서가 사용되므로 임의로 설정됩니다. 당신이 순서를 볼 수 있습니다 hash randomisation에 전환하는 경우 변동 : 나는 파이썬 2.7.8를 사용하고 있습니다으로

$ bin/python -R -c $'from enum import Enum\nclass Animal(Enum):\n cat = {0, 1}\n dog = {1, 2}\n fish = {2, 0}\n\nprint list(Animal)\n' 
[<Animal.dog: set([1, 2])>, <Animal.cat: set([0, 1])>, <Animal.fish: set([0, 2])>] 
$ bin/python -R -c $'from enum import Enum\nclass Animal(Enum):\n cat = {0, 1}\n dog = {1, 2}\n fish = {2, 0}\n\nprint list(Animal)\n' 
[<Animal.fish: set([0, 2])>, <Animal.cat: set([0, 1])>, <Animal.dog: set([1, 2])>] 
$ bin/python -R -c $'from enum import Enum\nclass Animal(Enum):\n cat = {0, 1}\n dog = {1, 2}\n fish = {2, 0}\n\nprint list(Animal)\n' 
[<Animal.fish: set([0, 2])>, <Animal.dog: set([1, 2])>, <Animal.cat: set([0, 1])>] 

나는 당신의 TypeError 보지 않았다; issue 8743에 대한 수정으로 collections.Set() ABCset() 개 개체로 사용할 수있게 될 때까지 set 개체는 실제로 주문할 수 없습니다.

이 문제에 대한 픽스는 Python 2.7.8의 일부이며 개인적으로 이전 동작은 버그라고 생각합니다. 대신 예외를 발생시키기보다는 NotImplemented 센티넬이 반환되어야합니다. 당신이 값에 대한 유형의 혼합에 열거을 가지고이 경우 2.7.8로 업그레이드 할 수있을 때까지

그래서, 당신은 __order__ 속성이 붙어있다.set은 이종 유형을 주문할 때 좋지 않지만 enum34의 잘못입니다.

+0

우리는 이론적으로 파이썬 2의 코드 객체에 접근 할 수 없습니까? 인트로 스펙을 사용하여 정의 순서를 복구 하시겠습니까? – wim

+1

@wim : 클래스를 정의하는 원래 코드 객체를 얻는 것조차 어렵습니다. 기능 범위가 없기 때문입니다. 먼저 원본 모듈 바이트 코드를로드해야합니다. 즉, 먼저 해당 데이터에 액세스 할 수 있어야합니다. 압축 된 모듈 아카이브 지원이 필요합니다. 이것은 'STORE_FAST' 바이트 코드 순서를 저장하는 이름 등으로 매핑해야하는 고통과 별개입니다. –

+0

@wim : 자이 썬을 지원합니다. IronPython 및 PyPy를 사용하므로 바이트 코드와 같은 구현 세부 정보를 사용할 수 있습니다. –

관련 문제