[Python] enum 구현 Develop Tip

C나 C# 등에서는 enum 형이 있습니다.

다음은 C인 경우의 예 입니다.
typedef _three enum {
ZERO,
ONE,
TWO
} t_three;

라는 식으로 지정하면,
소스 내에서

t_three a;
int i = a.ONE;
과 같은 식으로 지정할 수 있습니다.

파이썬에서는 그에 해당되는 디폴트 enum 형이 없었습니다.

그래서 찾아보았더니,
해당 스택오버플로우에 그 답이 있더군요.
역시나 수많은 개발자들이 물어보았더군요.

결론은 다음과 같습니다.

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)

라는 함수를 만들면 간단히 해결됩니다.

그러면,

>>> Numbers = enum('ZERO', 'ONE', 'TWO')
>>> Numbers.ONE
1
>>> Numbers.TWO
2

와 같이 접근 가능하구요,

그 반대도 찾을 수 있습니다.

>>> Numbers.reverse_mapping[1]
'ONE'
와 같은 식이지요.

우와 이런 함수를 어떻게 생각하고 만들었을까 궁금해 지더군요.

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)

하나씩 뜯어 보았습니다.

>>> Numbers = enum('ZERO', 'ONE', 'TWO', FIVE=5, SIX=6)
라고 호출해 보겠습니다

    enums = dict(zip(sequential, range(len(sequential))), **named)

>>> sequential
('ONE', 'TWO', 'THREE')
정상 적인 패러미터 입니다.

>>> named
{'SIX': 6, 'FIVE': 5}
값을 지정한 패러미터 입니다.

>>> zip(sequential, range(len(sequential)))
[('ONE', 0), ('TWO', 1), ('THREE', 2)]
정상 패러미터를 zip 을 이용하여 0,1,2 인덱싱을 갖는 순서쌍으로 만듦니다.

>>> dict(zip(sequential, range(len(sequential))), **named)
{'FIVE': 5, 'SIX': 6, 'THREE': 2, 'TWO': 1, 'ONE': 0}
나머지 named parameter도 같이 포함한 dict로 만듦니다.

>>> enums=dict(zip(sequential, range(len(sequential))), **named)
결국 enums 는 위와 같은 결과를 갖습니다.


    reverse = dict((value, key) for key, value in enums.iteritems())

>>> dict((value, key) for key, value in enums.iteritems())
{0: 'ONE', 1: 'TWO', 2: 'THREE', 5: 'FIVE', 6: 'SIX'}
reverse는 위와 같은 key,value가 뒤집힌 dict를 갖습니다.


    enums['reverse_mapping'] = reverse

>>> enums
{'reverse_mapping': {0: 'ONE', 1: 'TWO', 2: 'THREE', 5: 'FIVE', 6: 'SIX'}, 'SIX': 6, 'THREE': 2, 'TWO': 1, 'FIVE': 5, 'ONE': 0}
reverse_mapping을 포함한 dict 가 됩니다.


    return type('Enum', (), enums)

이제 마지막 줄 입니다.

type() 은 python의 built-in 함수 입니다.

type(object)
type(namebasesdict)

With one argument, return the type of an object. The return value is a type object. The isinstance() built-in function is recommended for testing the type of an object.

With three arguments, return a new type object. This is essentially a dynamic form of the class statement. Thename string is the class name and becomes the __name__ attribute; the bases tuple itemizes the base classes and becomes the __bases__ attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the __dict__ attribute. For example, the following two statements create identical type objects:

>>>
>>> class X(object):...     a = 1...>>> X = type('X', (object,), dict(a=1))

New in version 2.2.

위와 같은 설명을 갖습니다.

즉 그 결과값은 
x.__name__ 은 'Enum' 이고,
x.__bases__는 () 이며,
x. 안의 내용은 enums 인 type 이 되는 것이지요.

정말이지 이런식으로 dynamic 하게 언어를 만들었다는 것 자체도 훌륭하거니와
더불어 이런식의 결과를 만드는 프로그래머들도 참 대단하다는 생각이 듭니다.

참고로, 아래와 같은 직접 만드는 방법과,

Numbers=enum('ZERO', 'ONE','TWO','THREE',FIVE=5,SIX=6)
print Numbers.FIVE
print Numbers.reverse_mapping[6]

tuple과 dict 패러미터로 만드는 방법은
seq=('ZERO', 'ONE','TWO','THREE')
named={'FIVE':5, 'SIX':6}
Numbers=enum(*seq,**named)
print Numbers.FIVE
print Numbers.reverse_mapping[6]

동일한 결과를 나타냅니다.

어느분께는 도움이 되셨기를...


덧글

  • 2013/06/05 14:07 # 답글 비공개

    비공개 덧글입니다.
  • 2013/06/05 14:54 # 비공개

    비공개 답글입니다.
  • 졸린미어캣 2015/01/27 09:03 # 답글

    글 잘 보구갑니당^^ 자세히 잘 써주셧네요 ㅋ
  • 지훈현서아빠 2015/01/27 09:09 #

    도움이 되셨다니 저의 보람입니다~
  • 제임스 2016/03/22 15:45 # 답글

    얼마 전부터 python을 적용해서 프로젝트를 해보고 있는데
    python 궁금한 점을 검색해보면 문창님을 뵙겠구나 하며 말이죠.
    오늘 드디어 만났네요. ^^

    enum function은 참 독특하네요.
  • 지훈현서아빠 2016/03/22 16:45 #

    ㅎㅎ 젬스님께서도 드디어 검색엔진을 통해 제 블로그로 왕립해 주셨군요~
    고맙습니다 ^^
  • kym2732 2016/10/31 17:13 # 삭제 답글

    한 가지 궁금한게 있는데요.. 허접한 질문일지도 모르겠습니다만..
    reverse_mapping[i] 와 같이 사용하고 싶은데 enum 타입의 개수를 알 수 있나요?
    len(..)와 같이 사용하면 에러를 발생시키네요..
댓글 입력 영역

구글애드텍스트