파이썬에서 enum의 원소를 random하게 가져오는 방법을 알아보겠습니다.

 


 먼저, Enum을 상속받은 A 클래스를 보겠습니다. 이름이 A이고 값이 1인 것, 이름이 B이고 값이 3인 것, 이름이 C이고 값이 5인 것, 이름이 D이고 값이 7인 것이 있습니다.

 

 랜덤하게 뽑을 것이므로, choice와 같은 것이 필요한 것은 자명해 보입니다. 그런데 이것은 sequence가 필요하다고 뜹니다. 시퀀스의 대표적인 것은 list이니, enum의 데이터를 list로 변환해야겠네요.

 

 rd.choice(list(A))를 해 주면, A에 있는 item 중에 랜덤하게 하나를 뽑습니다. 이게 다입니다.

 

 실행 결과는 A.a, A.b, A.c, A.d 중에 하나가 나옵니다. 즉, list(enum_class_name)은, enum class인 enum_class_name에 있는 원소들을 리스트로 변환해 줍니다.

 


 코드가 어떻게 실행되나 보겠습니다. Enum에서 metaclass는 EnumType임을 알 수 있습니다. 이 클래스 안에 무엇이 있을까요?

 

 놀랍게도 __iter__ 이라는 함수에서 멈추게 됩니다. __iter__는 이터레이터를 반환해 주는 함수인데요. member_names_를 돌면서, _member_map_에 있는 것들을 꺼내옴을 알 수 있습니다. 소괄호로 묶여져 있는 것은 generator를 리턴함을 의미합니다. 결국, enum에 선언된 아이템들을 모두 가져오는 무언가를 generator로 감싼 형태가 됩니다.

 

  이제 이 generator를 list의 생성자의 인자로 넘기면, 멤버들을 모두 가지고 있는 list를 리턴하게 됩니다.

 

 

 정리하면, list(A)에서 넘겨지는 타입은 generator입니다. 한 번 next가 불릴 때 마다, A, B, C, D를 가리키는 generator가 나오게 됩니다. 중간에 metaclass의 __iter__가 호출되는 것을 보면 알 수 있습니다. generator를 list의 생성자로 넘기게 되면, 리스트가 초기화 되는 과정에서 내부에서 리턴된 generator의 원소들이 소모되게 됩니다.

 

 고로, list(A)를 했다면 아래와 같이 나옵니다.

 

 

 이제, 구축된 리스트를 바탕으로 choice를 돌리면, 4개의 enum 원소 중에 하나가 뽑히게 됩니다.

 

 

 여담으로 reversed(A)도 있습니다. 이 경우, 거꾸로 나오게 됩니다. enum의 원소 중에 랜덤하게 뽑는다는 문제와는 상관은 없습니다만, 알아두면 좋을 듯 싶습니다. 정리하면 Enum을 상속받은 A가 있을 때, list(A)는 A의 원소들을 모두 가져오는 generator를 넘깁니다.

 

 결국 list(A)는 A의 원소들을 모두 가지고 있을 겁니다. 이제 우리는 이 리스트에서 random하게 하나 뽑기만 하면 됩니다. 제너레이터에 대한 조금 더 자세한 설명은 여기를 보셔도 되겠습니다.