답변:
PEP 435에 설명 된대로 열거 형이 Python 3.4에 추가되었습니다 . 또한 pypi 에서 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 및 2.4 로 백 포트 되었습니다 .
고급 Enum 기술을 사용하려면 aenum 라이브러리 (2.7, 3.3 이상,.와 동일한 작성자)를 사용해보십시오 enum34
. 코드는 py2와 py3 사이에서 완벽하게 호환되지 않습니다 (예 : __order__
python 2에 필요 ).
enum34
수행$ pip install enum34
aenum
수행$ pip install aenum
설치 enum
(아무 번호는) 완전히 다른 호환되지 않는 버전을 설치하지 않습니다.
from enum import Enum # for enum34, or the stdlib version
# from aenum import Enum # for the aenum version
Animal = Enum('Animal', 'ant bee cat dog')
Animal.ant # returns <Animal.ant: 1>
Animal['ant'] # returns <Animal.ant: 1> (string lookup)
Animal.ant.name # returns 'ant' (inverse lookup)
또는 동등하게 :
class Animal(Enum):
ant = 1
bee = 2
cat = 3
dog = 4
이전 버전에서 열거 형을 달성하는 한 가지 방법은 다음과 같습니다.
def enum(**enums):
return type('Enum', (), enums)
다음과 같이 사용됩니다.
>>> Numbers = enum(ONE=1, TWO=2, THREE='three')
>>> Numbers.ONE
1
>>> Numbers.TWO
2
>>> Numbers.THREE
'three'
다음과 같은 방법으로 자동 열거를 쉽게 지원할 수도 있습니다.
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
return type('Enum', (), enums)
다음과 같이 사용됩니다.
>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ZERO
0
>>> Numbers.ONE
1
값을 다시 이름으로 변환하는 지원은 다음과 같이 추가 할 수 있습니다.
def enum(*sequential, **named):
enums = dict(zip(sequential, range(len(sequential))), **named)
reverse = dict((value, key) for key, value in enums.iteritems())
enums['reverse_mapping'] = reverse
return type('Enum', (), enums)
이것은 해당 이름을 가진 모든 것을 덮어 쓰지만, 열거 형을 출력으로 렌더링하는 데 유용합니다. 역 매핑이 존재하지 않으면 KeyError가 발생합니다. 첫 번째 예를 들면 다음과 같습니다.
>>> Numbers.reverse_mapping['three']
'THREE'
**named
이전 버전의 enum 함수에서 var kwargs ( )는 다음과 같은 사용자 정의 값을 지원합니다.enum("blue", "red", "green", black=0)
PEP 435 이전에는 Python에는 동등한 기능이 없었지만 직접 구현할 수있었습니다.
나 자신, 나는 이것을 간단하게 유지하는 것을 좋아한다.
class Animal:
DOG = 1
CAT = 2
x = Animal.DOG
Python 3.4 ( PEP 435 )에서 Enum 을 기본 클래스로 만들 수 있습니다 . 이것은 PEP에 설명 된 약간의 추가 기능을 제공합니다. 예를 들어 열거 형 멤버는 정수와 구별되며 a name
와 a 로 구성 value
됩니다.
class Animal(Enum):
DOG = 1
CAT = 2
print(Animal.DOG)
# <Animal.DOG: 1>
print(Animal.DOG.value)
# 1
print(Animal.DOG.name)
# "DOG"
값을 입력하지 않으려면 다음 바로 가기를 사용하십시오.
class Animal(Enum):
DOG, CAT = range(2)
Enum
구현 은리스트로 변환 될 수 있고 반복 가능하다 . 멤버의 순서는 선언 순서이며 값과 관련이 없습니다. 예를 들면 다음과 같습니다.
class Animal(Enum):
DOG = 1
CAT = 2
COW = 0
list(Animal)
# [<Animal.DOG: 1>, <Animal.CAT: 2>, <Animal.COW: 0>]
[animal.value for animal in Animal]
# [1, 2, 0]
Animal.CAT in Animal
# True
object()
합니다.
다음은 하나의 구현입니다.
class Enum(set):
def __getattr__(self, name):
if name in self:
return name
raise AttributeError
사용법은 다음과 같습니다.
Animals = Enum(["DOG", "CAT", "HORSE"])
print(Animals.DOG)
__setattr__(self, name, value)
어쩌면 __delattr__(self, name)
당신이 실수로 작성하는 경우 그래서 Animals.DOG = CAT
, 그것은 자동으로 실패합니다.
Animals.DOG
. 또한, constats의 값은 문자열이므로 이러한 상수와의 비교는 정수가 값으로 허용되는 경우보다 느립니다.
setattr()
내부의 함수를 사용해 보았습니다 . 나는 이것이 같은 방식으로 작동한다고 가정합니다. AttributeError__init__()
__getattr__()
try-except
블록 멤버십 설정을 어떻게 확인 합니까?
숫자 값이 필요한 경우 가장 빠른 방법은 다음과 같습니다.
dog, cat, rabbit = range(3)
Python 3.x에서는 끝에 별표 표시된 자리 표시자를 추가 할 수 있습니다. 메모리를 낭비하지 않고 계산할 수없는 경우 나머지 범위 값을 모두 흡수합니다.
dog, cat, rabbit, horse, *_ = range(100)
당신을위한 최선의 해결책은 당신이 가짜 에서 요구하는 것에 달려 있습니다 enum
.
간단한 열거 형 :
다른 항목을 식별하는 이름enum
목록 만 필요한 경우 Mark Harrison 의 솔루션 (위)이 훌륭합니다.
Pen, Pencil, Eraser = range(0, 3)
를 사용하면 시작 값range
을 설정할 수 있습니다 .
Pen, Pencil, Eraser = range(9, 12)
위의 항목 외에도 항목이 일종의 컨테이너 에 속 해야하는 경우 클래스에 포함하십시오.
class Stationery:
Pen, Pencil, Eraser = range(0, 3)
열거 형 항목을 사용하려면 컨테이너 이름과 항목 이름을 사용해야합니다.
stype = Stationery.Pen
복잡한 열거 형 :
열거 형의 열거 목록이나 열거 형의보다 복잡한 사용의 경우 이러한 솔루션으로는 충분하지 않습니다. Python Cookbook에 게시 된 Python 에서 열거 시뮬레이션을 위한 Will Ware의 레시피를 확인할 수 있습니다. 온라인 버전은 여기에서 구할 수 있습니다 .
더 많은 정보:
PEP 354 : Python의 열거에는 Python의 열거에 대한 흥미로운 제안과 거부 이유가 있습니다.
range
가 0 인 경우 첫 번째 인수를 생략 할 수 있습니다
my_enum = dict(map(reversed, enumerate(str.split('Item0 Item1 Item2'))))
입니다. 그런 다음 my_enum
조회에 사용될 수 있습니다. 예를 들어 my_enum['Item0']
시퀀스에 대한 색인 일 수 있습니다. str.split
중복이있는 경우 예외를 발생시키는 함수로 결과를 랩핑 할 수 있습니다 .
Flag1, Flag2, Flag3 = [2**i for i in range(3)]
Java JDK 5 이전에 사용 된 typesafe 열거 형 패턴에는 여러 가지 장점이 있습니다. Alexandru의 답변과 마찬가지로 클래스를 만들고 클래스 수준 필드는 열거 형 값입니다. 그러나 열거 형 값은 작은 정수가 아닌 클래스의 인스턴스입니다. 이것은 열거 형 값이 실수로 작은 정수와 동등하게 비교되지 않는다는 이점이 있습니다. 인쇄 방법을 제어하고, 유용한 경우 임의의 방법을 추가하고 isinstance를 사용하여 어설 션을 만들 수 있습니다.
class Animal:
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
def __repr__(self):
return "<Animal: %s>" % self
Animal.DOG = Animal("dog")
Animal.CAT = Animal("cat")
>>> x = Animal.DOG
>>> x
<Animal: dog>
>>> x == 1
False
python-dev 의 최근 스레드는 다음을 포함하여 야생에 두 개의 열거 형 라이브러리가 있다고 지적했습니다.
Enum 클래스는 하나의 라이너가 될 수 있습니다.
class Enum(tuple): __getattr__ = tuple.index
사용 방법 (정방향 및 역방향 조회, 키, 값, 항목 등)
>>> State = Enum(['Unclaimed', 'Claimed'])
>>> State.Claimed
1
>>> State[1]
'Claimed'
>>> State
('Unclaimed', 'Claimed')
>>> range(len(State))
[0, 1]
>>> [(k, State[k]) for k in range(len(State))]
[(0, 'Unclaimed'), (1, 'Claimed')]
>>> [(k, getattr(State, k)) for k in State]
[('Unclaimed', 0), ('Claimed', 1)]
in
키워드를 사용하여 깔끔한 멤버를 검색 할 수 있습니다. 사용법 :'Claimed' in Enum(['Unclaimed', 'Claimed'])
그래서 동의합니다. 파이썬에서 타입 안전을 강요하지는 않지만 어리석은 실수로부터 자신을 보호하고 싶습니다. 그래서 우리는 이것에 대해 어떻게 생각합니까?
class Animal(object):
values = ['Horse','Dog','Cat']
class __metaclass__(type):
def __getattr__(self, name):
return self.values.index(name)
열거 형을 정의 할 때 가치 충돌을 피할 수 있습니다.
>>> Animal.Cat
2
또 다른 편리한 장점이 있습니다 : 정말 빠른 역방향 조회 :
def name_of(self, i):
return self.values[i]
Animal = Enum('horse', 'dog', 'cat')
. 또한 self.values에 누락 된 항목이있는 경우 getattr 에서 ValueError를 잡습니다 . 대신 제공된 이름 문자열로 AttributeError를 발생시키는 것이 좋습니다. 해당 영역에 대한 제한된 지식을 기반으로 Python 2.7에서 메타 클래스를 작동시킬 수 없었지만 사용자 정의 Enum 클래스는 직선 인스턴스 메소드에서 잘 작동합니다.
파이썬에는에 상응하는 빌트인이 없으며 enum
다른 답변에는 자체 구현 아이디어가 있습니다 ( 파이썬 요리 책 의 최상위 버전 에 관심이있을 수도 있습니다 ).
그러나 enum
C에서 호출이 필요한 상황에서는 일반적으로 간단한 문자열을 사용합니다 . 객체 / 속성이 구현되는 방식 때문에 (C) Python은 짧은 문자열로 매우 빠르게 작동하도록 최적화되어 있으므로 정수를 사용하면 실제로 성능상의 이점이 아닙니다. 오타 / 유효하지 않은 값으로부터 보호하기 위해 선택한 위치에 검사를 삽입 할 수 있습니다.
ANIMALS = ['cat', 'dog', 'python']
def take_for_a_walk(animal):
assert animal in ANIMALS
...
(클래스를 사용하는 것에 비해 한 가지 단점은 자동 완성의 이점을 잃어 버린다는 것입니다)
2013 년 5 월 10 일, Guido는 PEP 435 를 Python 3.4 표준 라이브러리 에 수용하기로 동의했습니다 . 이것은 파이썬이 마침내 열거를 기본적으로 지원한다는 것을 의미합니다!
Python 3.3, 3.2, 3.1, 2.7, 2.6, 2.5 및 2.4에 사용할 수있는 백 포트가 있습니다. enum34로 Pypi에 있습니다.
선언:
>>> from enum import Enum
>>> class Color(Enum):
... red = 1
... green = 2
... blue = 3
대표:
>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>
되풀이:
>>> for color in Color:
... print(color)
...
Color.red
Color.green
Color.blue
프로그래밍 방식의 액세스 :
>>> Color(1)
Color.red
>>> Color['blue']
Color.blue
자세한 내용 은 제안서를 참조하십시오 . 공식 문서가 곧 나올 것입니다.
파이썬에서 열거 형을 다음과 같이 정의하는 것을 선호합니다.
class Animal:
class Dog: pass
class Cat: pass
x = Animal.Dog
정수가 고유하다는 것을 걱정할 필요가 없기 때문에 정수를 사용하는 것보다 버그가 방지됩니다 (예 : Dog = 1 및 Cat = 1이라고 말하면 망할 것입니다).
오타에 대해 걱정할 필요가 없으므로 문자열을 사용하는 것보다 버그가 더 적습니다 (예 : x == "catt"는 자동으로 실패하지만 x == Animal.Catt는 런타임 예외입니다).
def M_add_class_attribs(attribs):
def foo(name, bases, dict_):
for v, k in attribs:
dict_[k] = v
return type(name, bases, dict_)
return foo
def enum(*names):
class Foo(object):
__metaclass__ = M_add_class_attribs(enumerate(names))
def __setattr__(self, name, value): # this makes it read-only
raise NotImplementedError
return Foo()
다음과 같이 사용하십시오.
Animal = enum('DOG', 'CAT')
Animal.DOG # returns 0
Animal.CAT # returns 1
Animal.DOG = 2 # raises NotImplementedError
고유 한 기호 만 원하고 값에 신경 쓰지 않으면이 줄을 바꾸십시오.
__metaclass__ = M_add_class_attribs(enumerate(names))
이것으로 :
__metaclass__ = M_add_class_attribs((object(), name) for name in names)
enum(names)
하기 enum(*names)
를 호출 할 때 다음 여분의 괄호를 드롭 할 수 -.
파이썬 3.4부터 열거 형에 대한 공식적인 지원이있을 것입니다. Python 3.4 documentation page에서 문서와 예제를 찾을 수 있습니다 .
열거는 클래스 구문을 사용하여 작성되므로 쉽게 읽고 쓸 수 있습니다. 대체 작성 방법은 Functional API에 설명되어 있습니다. 열거를 정의하려면 다음과 같이 Enum을 서브 클래스로 만드십시오.
from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
흠 ... 열거 형에 가장 가까운 것은 다음과 같이 정의 된 사전이라고 생각합니다.
months = {
'January': 1,
'February': 2,
...
}
또는
months = dict(
January=1,
February=2,
...
)
그런 다음 상수의 기호 이름을 다음과 같이 사용할 수 있습니다.
mymonth = months['January']
튜플 목록 또는 튜플 튜플과 같은 다른 옵션이 있지만 사전은 값에 액세스 할 수있는 "기호"(일정한 문자열) 방법을 제공하는 유일한 옵션입니다.
편집 : 나는 Alexandru의 대답도 좋아합니다!
다음을 사용하여 파이썬에서 열거 형을 구현하는 매우 간단한 또 다른 방법은 namedtuple
다음과 같습니다.
from collections import namedtuple
def enum(*keys):
return namedtuple('Enum', keys)(*keys)
MyEnum = enum('FOO', 'BAR', 'BAZ')
또는 대안 적으로
# With sequential number values
def enum(*keys):
return namedtuple('Enum', keys)(*range(len(keys)))
# From a dict / keyword args
def enum(**kwargs):
return namedtuple('Enum', kwargs.keys())(*kwargs.values())
하위 클래스 위의 메소드와 마찬가지로 set
다음을 허용합니다.
'FOO' in MyEnum
other = MyEnum.FOO
assert other == MyEnum.FOO
그러나 다른 키와 값을 가질 수 있으므로 더 많은 유연성이 있습니다. 이것은 허용
MyEnum.FOO < MyEnum.BAR
순차적 인 숫자 값을 채우는 버전을 사용하는 경우 예상대로 작동합니다.
내가 사용하는 것 :
class Enum(object):
def __init__(self, names, separator=None):
self.names = names.split(separator)
for value, name in enumerate(self.names):
setattr(self, name.upper(), value)
def tuples(self):
return tuple(enumerate(self.names))
사용하는 방법:
>>> state = Enum('draft published retracted')
>>> state.DRAFT
0
>>> state.RETRACTED
2
>>> state.FOO
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Enum' object has no attribute 'FOO'
>>> state.tuples()
((0, 'draft'), (1, 'published'), (2, 'retracted'))
따라서 이것은 장고 모델에서 선택으로 사용할 state.PUBLISHED 및 두 개의 튜플과 같은 정수 상수를 제공합니다.
이것은 내가 본 것 중 가장 좋은 것입니다 : "파이썬의 퍼스트 클래스 열거 형"
http://code.activestate.com/recipes/413486/
그것은 당신에게 클래스를 제공하고 클래스는 모든 열거 형을 포함합니다. 열거 형은 서로 비교할 수 있지만 특별한 가치는 없습니다. 정수 값으로 사용할 수 없습니다. (정수 값인 C 열거 형에 익숙하기 때문에 처음에는 저항했습니다.하지만 정수로 사용할 수 없으면 실수로 정수로 사용할 수 없으므로 전반적으로 승리라고 생각합니다 .) 각 열거 형은 고유 한 값입니다. 열거 형을 인쇄하고 반복 할 수 있으며 열거 형 값이 열거 형에 있는지 테스트 할 수 있습니다. 꽤 완전하고 매끄 럽습니다.
편집 (cfi) : 위의 링크는 Python 3과 호환되지 않습니다. 다음은 파이썬 3에 대한 enum.py 포트입니다.
def cmp(a,b):
if a < b: return -1
if b < a: return 1
return 0
def Enum(*names):
##assert names, "Empty enums are not supported" # <- Don't like empty enums? Uncomment!
class EnumClass(object):
__slots__ = names
def __iter__(self): return iter(constants)
def __len__(self): return len(constants)
def __getitem__(self, i): return constants[i]
def __repr__(self): return 'Enum' + str(names)
def __str__(self): return 'enum ' + str(constants)
class EnumValue(object):
__slots__ = ('__value')
def __init__(self, value): self.__value = value
Value = property(lambda self: self.__value)
EnumType = property(lambda self: EnumType)
def __hash__(self): return hash(self.__value)
def __cmp__(self, other):
# C fans might want to remove the following assertion
# to make all enums comparable by ordinal value {;))
assert self.EnumType is other.EnumType, "Only values from the same enum are comparable"
return cmp(self.__value, other.__value)
def __lt__(self, other): return self.__cmp__(other) < 0
def __eq__(self, other): return self.__cmp__(other) == 0
def __invert__(self): return constants[maximum - self.__value]
def __nonzero__(self): return bool(self.__value)
def __repr__(self): return str(names[self.__value])
maximum = len(names) - 1
constants = [None] * len(names)
for i, each in enumerate(names):
val = EnumValue(i)
setattr(EnumClass, each, val)
constants[i] = val
constants = tuple(constants)
EnumType = EnumClass()
return EnumType
if __name__ == '__main__':
print( '\n*** Enum Demo ***')
print( '--- Days of week ---')
Days = Enum('Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su')
print( Days)
print( Days.Mo)
print( Days.Fr)
print( Days.Mo < Days.Fr)
print( list(Days))
for each in Days:
print( 'Day:', each)
print( '--- Yes/No ---')
Confirmation = Enum('No', 'Yes')
answer = Confirmation.No
print( 'Your answer is not', ~answer)
.__int__()
메소드는 열거 형에 대한 예외를 제기해야합니다. 그러나 가치를 얻는 방법이 있어야합니다. 클래스 정의 시간에 특정 정수 값을 설정할 수 있으므로 stat
모듈 의 상수와 같은 것에 열거 형을 사용할 수 있습니다 .
이진 파일 형식을 디코딩하기 위해 Enum 클래스가 필요할 때가 있습니다. 내가 원했던 기능은 간결한 열거 형 정의, 정수 값 또는 문자열로 열거 형 인스턴스를 자유롭게 만들 수있는 기능 및 유용한 repr
평가입니다. 내가 끝내었던 것은 다음과 같습니다.
>>> class Enum(int):
... def __new__(cls, value):
... if isinstance(value, str):
... return getattr(cls, value)
... elif isinstance(value, int):
... return cls.__index[value]
... def __str__(self): return self.__name
... def __repr__(self): return "%s.%s" % (type(self).__name__, self.__name)
... class __metaclass__(type):
... def __new__(mcls, name, bases, attrs):
... attrs['__slots__'] = ['_Enum__name']
... cls = type.__new__(mcls, name, bases, attrs)
... cls._Enum__index = _index = {}
... for base in reversed(bases):
... if hasattr(base, '_Enum__index'):
... _index.update(base._Enum__index)
... # create all of the instances of the new class
... for attr in attrs.keys():
... value = attrs[attr]
... if isinstance(value, int):
... evalue = int.__new__(cls, value)
... evalue._Enum__name = attr
... _index[value] = evalue
... setattr(cls, attr, evalue)
... return cls
...
그것을 사용하는 기발한 예 :
>>> class Citrus(Enum):
... Lemon = 1
... Lime = 2
...
>>> Citrus.Lemon
Citrus.Lemon
>>>
>>> Citrus(1)
Citrus.Lemon
>>> Citrus(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __new__
KeyError: 5
>>> class Fruit(Citrus):
... Apple = 3
... Banana = 4
...
>>> Fruit.Apple
Fruit.Apple
>>> Fruit.Lemon
Citrus.Lemon
>>> Fruit(1)
Citrus.Lemon
>>> Fruit(3)
Fruit.Apple
>>> "%d %s %r" % ((Fruit.Apple,)*3)
'3 Apple Fruit.Apple'
>>> Fruit(1) is Citrus.Lemon
True
주요 특징들:
str()
, int()
및 repr()
모든 생산 가장 유용 가능한 출력은 enumartion 각각의 이름, 그 정수 값을 평가하는 것은 열거을 맞댄 것을 파이썬 식.is
__instancecheck__
메소드 를 정의합니다 . 클래스는 인스턴스의 모음이 아니므 1 in Fruit
로 터무니 없습니다. 그러나 링크 된 버전은 isinstance(1, Fruit)
클래스와 인스턴스의 개념에서 더 정확한 것을 지원 합니다.
Python의 새로운 표준은 PEP 435 이므로 Enum 클래스는 다음 버전의 Python에서 사용할 수 있습니다.
>>> from enum import Enum
그러나 지금 사용하기 시작 하면 PEP에 동기를 부여한 원본 라이브러리 를 설치할 수 있습니다 .
$ pip install flufl.enum
그런 다음 온라인 가이드에 따라 사용할 수 있습니다 .
>>> from flufl.enum import Enum
>>> class Colors(Enum):
... red = 1
... green = 2
... blue = 3
>>> for color in Colors: print color
Colors.red
Colors.green
Colors.blue
def enum(*sequential, **named):
enums = dict(zip(sequential, [object() for _ in range(len(sequential))]), **named)
return type('Enum', (), enums)
이름을 지정하면 문제가되지만 값 대신 객체를 만들지 않으면 다음과 같이 할 수 있습니다.
>>> DOG = enum('BARK', 'WALK', 'SIT')
>>> CAT = enum('MEOW', 'WALK', 'SIT')
>>> DOG.WALK == CAT.WALK
False
여기에있는 다른 구현을 사용할 때 (또한 예제에서 명명 된 인스턴스를 사용할 때) 다른 열거 형의 객체를 비교하려고 시도하지 않아야합니다. 여기에 가능한 함정이 있습니다.
>>> DOG = enum('BARK'=1, 'WALK'=2, 'SIT'=3)
>>> CAT = enum('WALK'=1, 'SIT'=2)
>>> pet1_state = DOG.BARK
>>> pet2_state = CAT.WALK
>>> pet1_state == pet2_state
True
이케!
나는 Alec Thomas의 솔루션 (http://stackoverflow.com/a/1695250)을 정말 좋아합니다.
def enum(**enums):
'''simple constant "enums"'''
return type('Enum', (object,), enums)
우아하고 깔끔하게 보이지만 지정된 속성으로 클래스를 만드는 함수 일뿐입니다.
함수를 약간 수정하면 좀 더 '열거'하도록 할 수 있습니다.
참고 : pygtk의 새로운 스타일 'enum'의 동작을 재현하여 다음 예제를 만들었습니다 (Gtk.MessageType.WARNING).
def enum_base(t, **enums):
'''enums with a base class'''
T = type('Enum', (t,), {})
for key,val in enums.items():
setattr(T, key, T(val))
return T
지정된 형식을 기준으로 열거 형을 만듭니다. 이전 함수와 같은 속성 액세스를 제공하는 것 외에도 유형과 관련하여 Enum을 기대하는 것처럼 작동합니다. 또한 기본 클래스를 상속합니다.
예를 들어, 정수 열거 형 :
>>> Numbers = enum_base(int, ONE=1, TWO=2, THREE=3)
>>> Numbers.ONE
1
>>> x = Numbers.TWO
>>> 10 + x
12
>>> type(Numbers)
<type 'type'>
>>> type(Numbers.ONE)
<class 'Enum'>
>>> isinstance(x, Numbers)
True
이 방법으로 수행 할 수있는 또 다른 흥미로운 점은 내장 방법을 재정 의하여 특정 동작을 사용자 정의하는 것입니다.
def enum_repr(t, **enums):
'''enums with a base class and repr() output'''
class Enum(t):
def __repr__(self):
return '<enum {0} of type Enum({1})>'.format(self._name, t.__name__)
for key,val in enums.items():
i = Enum(val)
i._name = key
setattr(Enum, key, i)
return Enum
>>> Numbers = enum_repr(int, ONE=1, TWO=2, THREE=3)
>>> repr(Numbers.ONE)
'<enum ONE of type Enum(int)>'
>>> str(Numbers.ONE)
'1'
PyPI 의 enum 패키지 는 강력한 enum 구현을 제공합니다. 이전 답변은 PEP 354를 언급했습니다. 이것은 거부되었지만 제안은 http://pypi.python.org/pypi/enum 으로 구현되었습니다 .
사용법이 쉽고 우아합니다.
>>> from enum import Enum
>>> Colors = Enum('red', 'blue', 'green')
>>> shirt_color = Colors.green
>>> shirt_color = Colors[2]
>>> shirt_color > Colors.red
True
>>> shirt_color.index
2
>>> str(shirt_color)
'green'
열거 형에 클래스 상수를 사용한다는 Alexandru의 제안은 잘 작동합니다.
또한 사람이 읽을 수있는 문자열 표현을 찾기 위해 각 상수 집합에 대한 사전을 추가하고 싶습니다.
이것은 두 가지 목적을 제공합니다.
class Animal:
TYPE_DOG = 1
TYPE_CAT = 2
type2str = {
TYPE_DOG: "dog",
TYPE_CAT: "cat"
}
def __init__(self, type_):
assert type_ in self.type2str.keys()
self._type = type_
def __repr__(self):
return "<%s type=%s>" % (
self.__class__.__name__, self.type2str[self._type].upper())
다음은 내가 찾은 몇 가지 다른 특성을 가진 접근법입니다.
가장 중요한 것은 다른 유형의 열거 형 간의 비교를 방지하는 것입니다 !
http://code.activestate.com/recipes/413486-first-class-enums-in-python 기반으로합니다 .
이 접근 방식과 다른 점을 설명하기 위해 많은 doctest가 여기에 포함되었습니다.
def enum(*names):
"""
SYNOPSIS
Well-behaved enumerated type, easier than creating custom classes
DESCRIPTION
Create a custom type that implements an enumeration. Similar in concept
to a C enum but with some additional capabilities and protections. See
http://code.activestate.com/recipes/413486-first-class-enums-in-python/.
PARAMETERS
names Ordered list of names. The order in which names are given
will be the sort order in the enum type. Duplicate names
are not allowed. Unicode names are mapped to ASCII.
RETURNS
Object of type enum, with the input names and the enumerated values.
EXAMPLES
>>> letters = enum('a','e','i','o','u','b','c','y','z')
>>> letters.a < letters.e
True
## index by property
>>> letters.a
a
## index by position
>>> letters[0]
a
## index by name, helpful for bridging string inputs to enum
>>> letters['a']
a
## sorting by order in the enum() create, not character value
>>> letters.u < letters.b
True
## normal slicing operations available
>>> letters[-1]
z
## error since there are not 100 items in enum
>>> letters[99]
Traceback (most recent call last):
...
IndexError: tuple index out of range
## error since name does not exist in enum
>>> letters['ggg']
Traceback (most recent call last):
...
ValueError: tuple.index(x): x not in tuple
## enums must be named using valid Python identifiers
>>> numbers = enum(1,2,3,4)
Traceback (most recent call last):
...
AssertionError: Enum values must be string or unicode
>>> a = enum('-a','-b')
Traceback (most recent call last):
...
TypeError: Error when calling the metaclass bases
__slots__ must be identifiers
## create another enum
>>> tags = enum('a','b','c')
>>> tags.a
a
>>> letters.a
a
## can't compare values from different enums
>>> letters.a == tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
>>> letters.a < tags.a
Traceback (most recent call last):
...
AssertionError: Only values from the same enum are comparable
## can't update enum after create
>>> letters.a = 'x'
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'a' is read-only
## can't update enum after create
>>> del letters.u
Traceback (most recent call last):
...
AttributeError: 'EnumClass' object attribute 'u' is read-only
## can't have non-unique enum values
>>> x = enum('a','b','c','a')
Traceback (most recent call last):
...
AssertionError: Enums must not repeat values
## can't have zero enum values
>>> x = enum()
Traceback (most recent call last):
...
AssertionError: Empty enums are not supported
## can't have enum values that look like special function names
## since these could collide and lead to non-obvious errors
>>> x = enum('a','b','c','__cmp__')
Traceback (most recent call last):
...
AssertionError: Enum values beginning with __ are not supported
LIMITATIONS
Enum values of unicode type are not preserved, mapped to ASCII instead.
"""
## must have at least one enum value
assert names, 'Empty enums are not supported'
## enum values must be strings
assert len([i for i in names if not isinstance(i, types.StringTypes) and not \
isinstance(i, unicode)]) == 0, 'Enum values must be string or unicode'
## enum values must not collide with special function names
assert len([i for i in names if i.startswith("__")]) == 0,\
'Enum values beginning with __ are not supported'
## each enum value must be unique from all others
assert names == uniquify(names), 'Enums must not repeat values'
class EnumClass(object):
""" See parent function for explanation """
__slots__ = names
def __iter__(self):
return iter(constants)
def __len__(self):
return len(constants)
def __getitem__(self, i):
## this makes xx['name'] possible
if isinstance(i, types.StringTypes):
i = names.index(i)
## handles the more normal xx[0]
return constants[i]
def __repr__(self):
return 'enum' + str(names)
def __str__(self):
return 'enum ' + str(constants)
def index(self, i):
return names.index(i)
class EnumValue(object):
""" See parent function for explanation """
__slots__ = ('__value')
def __init__(self, value):
self.__value = value
value = property(lambda self: self.__value)
enumtype = property(lambda self: enumtype)
def __hash__(self):
return hash(self.__value)
def __cmp__(self, other):
assert self.enumtype is other.enumtype, 'Only values from the same enum are comparable'
return cmp(self.value, other.value)
def __invert__(self):
return constants[maximum - self.value]
def __nonzero__(self):
## return bool(self.value)
## Original code led to bool(x[0])==False, not correct
return True
def __repr__(self):
return str(names[self.value])
maximum = len(names) - 1
constants = [None] * len(names)
for i, each in enumerate(names):
val = EnumValue(i)
setattr(EnumClass, each, val)
constants[i] = val
constants = tuple(constants)
enumtype = EnumClass()
return enumtype
다음은 Alec Thomas 솔루션의 변형입니다 .
def enum(*args, **kwargs):
return type('Enum', (), dict((y, x) for x, y in enumerate(args), **kwargs))
x = enum('POOH', 'TIGGER', 'EEYORE', 'ROO', 'PIGLET', 'RABBIT', 'OWL')
assert x.POOH == 0
assert x.TIGGER == 1
이 솔루션은 목록으로 정의 된 열거에 대한 클래스를 얻는 간단한 방법입니다 (더 이상 성가신 정수 할당은 없습니다).
enumeration.py :
import new
def create(class_name, names):
return new.classobj(
class_name, (object,), dict((y, x) for x, y in enumerate(names))
)
example.py :
import enumeration
Colors = enumeration.create('Colors', (
'red',
'orange',
'yellow',
'green',
'blue',
'violet',
))
type(class_name, (object,), dict(...))
대신 사용 하지 않겠습니까?
원래 열거 제안 인 PEP 354 가 몇 년 전에 기각 되었지만 계속 재개됩니다. 어떤 종류의 열거 형이 3.2에 추가되도록 의도되었지만 3.3으로 되돌아 간 다음 잊어 버렸습니다. 그리고 이제 파이썬 3.4에 포함될 PEP 435가 있습니다. PEP 435의 참조 구현은입니다 flufl.enum
.
2013 년 4 월 현재, 사람들이 "무언가"가 무엇인지에 대해 합의 할 수있는 한, 3.4에서 표준 라이브러리에 무언가 를 추가해야한다는 일반적인 합의가 있는 것 같습니다 . 어려운 부분입니다. 2013 년 초 몇 달 동안 여기 와 여기 에서 시작하는 실과 6 개의 다른 실을 참조하십시오.
그 사이에 PyPI, ActiveState 등에는 수많은 새로운 디자인과 구현이 표시되므로 FLUFL 디자인이 마음에 들지 않으면 PyPI 검색을 시도하십시오 .
다음을 사용하십시오.
TYPE = {'EAN13': u'EAN-13',
'CODE39': u'Code 39',
'CODE128': u'Code 128',
'i25': u'Interleaved 2 of 5',}
>>> TYPE.items()
[('EAN13', u'EAN-13'), ('i25', u'Interleaved 2 of 5'), ('CODE39', u'Code 39'), ('CODE128', u'Code 128')]
>>> TYPE.keys()
['EAN13', 'i25', 'CODE39', 'CODE128']
>>> TYPE.values()
[u'EAN-13', u'Interleaved 2 of 5', u'Code 39', u'Code 128']
나는 장고 모델 선택에 그것을 사용했고, 그것은 매우 파이썬처럼 보입니다. 실제로 Enum은 아니지만 작업을 수행합니다.