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(name, bases, dict)
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]
동일한 결과를 나타냅니다.
어느분께는 도움이 되셨기를...
퍄 개멋져....
아름다움이 느껴진다
파이썬이나 제이드같은 언어는 극혐
언어들 이노옴 만들어 놓은 방식들이 그 언어의 특성을 잘 드러내주는 것 같다. C는 닥치고 성능. JAVA는 클래스밖에 모르는 바보ㅠㅠ. 파이슨은 ... 기본 enum을 안 줬더니 유저들이 흑마법을 부려서 만들어버렸다.
나름 재밌는데 왜 싫어하시나여 ㅎ
내가 맘대로 { } 해서 닫겠다는데 맘대로도 못하게 하고 코드 길어지면 텝 보기도 힘들고 으으
파이슨 덕타이핑이랑 1급 함수 쓰다가 C++로 돌아가면 느낌이 어떨런지... 딴건 몰라도 저 두개가 진짜 조흔 거 같음
덕타이핑 의도는 좋은데 약간 c의 포인터처럼 잘못된 결과 내놓기도 쉬울거 같음
이름만 정신 차리고 쓰면 되긴 하겠지만 좀 그런 면도 있는 거 같네염. 근데 C++ 템플릿이 이제 보니까 덕타이핑이었음 ㅁㄴㅇㄹ
ㅋㅋㅋㅋㅋㅋㅋㅋ 딕셔너리 활용도 ㅁㅊ ㅋㅋㅋㅋㅋㅋ