"enum" --- 열거형 지원
**********************

버전 3.4에 추가.

**소스 코드:** Lib/enum.py

======================================================================

열거형(enumeration)은 고유한 상숫값에 연결된 기호 이름(멤버)의 집합입
니다. 열거형 내에서, 멤버를 아이덴티티로 비교할 수 있고, 열거형 자체는
이터레이트 될 수 있습니다.

참고:

  Enum 멤버의 케이스열거형은 상수를 나타내는 데 사용되기 때문에 열거형
  멤버에 대해 대문자(UPPER_CASE) 이름을 사용하는 것이 좋으며, 예제에서
  는 이 스타일을 사용합니다.


모듈 내용
=========

이 모듈은 고유한 이름 집합과 값을 정의하는 데 사용할 수 있는 네 가지
열거형 클래스를 정의합니다: "Enum", "IntEnum", "Flag" 및 "IntFlag". 또
한 하나의 데코레이터 "unique()"와 하나의 도우미 "auto"를 정의합니다.

class enum.Enum

   열거형 상수를 만들기 위한 베이스 클래스. 대체 구성 문법은 함수형
   API 섹션을 참조하십시오.

class enum.IntEnum

   "int"의 서브 클래스이기도 한 열거형 상수를 만들기 위한 베이스 클래
   스.

class enum.IntFlag

   "IntFlag" 멤버십을 잃지 않고 비트 연산자를 사용하여 결합할 수 있는
   열거형 상수를 만들기 위한 베이스 클래스. "IntFlag" 멤버도 "int"의
   서브 클래스입니다.

class enum.Flag

   "Flag" 멤버십을 잃지 않고 비트 연산을 사용하여 결합할 수 있는 열거
   형 상수를 만들기 위한 베이스 클래스.

enum.unique()

   한 값에 하나의 이름 만 연결되도록 하는 Enum 클래스 데코레이터.

class enum.auto

   인스턴스는 Enum 멤버에 적절한 값으로 바뀝니다. 기본적으로, 초깃값은
   1부터 시작합니다.

버전 3.6에 추가: "Flag", "IntFlag", "auto"


Enum 만들기
===========

열거형은 "class" 문법을 사용하여 작성되므로 쉽게 읽고 쓸 수 있습니다.
대체 작성 방법은 함수형 API에 설명되어 있습니다. 열거형을 정의하려면,
다음과 같이 "Enum"을 서브 클래스 하십시오:

   >>> from enum import Enum
   >>> class Color(Enum):
   ...     RED = 1
   ...     GREEN = 2
   ...     BLUE = 3
   ...

참고:

  Enum 멤버 값멤버 값은 아무것이나 될 수 있습니다: "int", "str" 등. 정
  확한 값이 중요하지 않다면, "auto" 인스턴스를 사용할 수 있으며 적절한
  값이 선택됩니다. "auto"를 다른 값과 혼합 할 경우 주의를 기울여야 합
  니다.

참고:

  명명법

  * "Color" 클래스는 *열거형(enumeration)* (또는 *enum*) 입니다.

  * "Color.RED", "Color.GREEN" 등의 어트리뷰트는 *열거형 멤버
    (enumeration members)*(또는 *enum members*)이며 기능상 상수입니다.

  * 열거형 멤버에는 *이름(names)*과 *값(values)*이 있습니다
    ("Color.RED"의 이름은 "RED", "Color.BLUE"의 값은 "3", 등)

참고:

  "class" 문법을 사용하여 Enum을 만들더라도, Enum은 일반적인 파이썬 클
  래스가 아닙니다. 자세한 내용은 열거형은 어떻게 다릅니까? 를 참조하십
  시오.

열거형 멤버는 사람이 읽을 수 있는 문자열 표현을 갖습니다:

   >>> print(Color.RED)
   Color.RED

"repr"에는 더 자세한 정보가 있습니다:

   >>> print(repr(Color.RED))
   <Color.RED: 1>

열거형 멤버의 *형*은 그것이 속한 열거형입니다:

   >>> type(Color.RED)
   <enum 'Color'>
   >>> isinstance(Color.GREEN, Color)
   True
   >>>

Enum 멤버에는 항목 이름 만 포함하는 프로퍼티가 있습니다:

   >>> print(Color.RED.name)
   RED

열거형은 정의 순서로 이터레이션을 지원합니다:

   >>> class Shake(Enum):
   ...     VANILLA = 7
   ...     CHOCOLATE = 4
   ...     COOKIES = 9
   ...     MINT = 3
   ...
   >>> for shake in Shake:
   ...     print(shake)
   ...
   Shake.VANILLA
   Shake.CHOCOLATE
   Shake.COOKIES
   Shake.MINT

열거형 멤버는 해시 가능하므로, 딕셔너리와 집합에 사용할 수 있습니다:

   >>> apples = {}
   >>> apples[Color.RED] = 'red delicious'
   >>> apples[Color.GREEN] = 'granny smith'
   >>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
   True


열거형 멤버와 그들의 어트리뷰트에 프로그래밍 방식으로 액세스하기
================================================================

때로는 프로그래밍 방식으로 열거형의 멤버에 액세스하는 것이 유용합니다
(즉, 프로그램 작성 시간에 정확한 색상을 알 수 없어서 "Color.RED"를 쓸
수 없는 상황). "Enum"는 그런 액세스를 허용합니다:

   >>> Color(1)
   <Color.RED: 1>
   >>> Color(3)
   <Color.BLUE: 3>

*이름(name)*으로 열거형 멤버에 액세스하려면, 항목 액세스를 사용하십시
오:

   >>> Color['RED']
   <Color.RED: 1>
   >>> Color['GREEN']
   <Color.GREEN: 2>

열거형 멤버가 있고 "name"이나 "value"가 필요하면:

   >>> member = Color.RED
   >>> member.name
   'RED'
   >>> member.value
   1


열거형 멤버와 값 중복하기
=========================

이름이 같은 열거형 멤버가 두 개 있는 것은 유효하지 않습니다:

   >>> class Shape(Enum):
   ...     SQUARE = 2
   ...     SQUARE = 3
   ...
   Traceback (most recent call last):
   ...
   TypeError: Attempted to reuse key: 'SQUARE'

그러나, 두 열거형 멤버는 같은 값을 가질 수 있습니다. 같은 값을 가진 두
멤버 A와 B가 주어지면 (그리고 A가 먼저 정의되면), B는 A의 별칭입니다.
A와 B의 값을 통한 조회는 A를 반환합니다. B의 이름을 통한 조회도 A를 반
환합니다:

   >>> class Shape(Enum):
   ...     SQUARE = 2
   ...     DIAMOND = 1
   ...     CIRCLE = 3
   ...     ALIAS_FOR_SQUARE = 2
   ...
   >>> Shape.SQUARE
   <Shape.SQUARE: 2>
   >>> Shape.ALIAS_FOR_SQUARE
   <Shape.SQUARE: 2>
   >>> Shape(2)
   <Shape.SQUARE: 2>

참고:

  이미 정의된 어트리뷰트(다른 멤버, 메서드 등)와 같은 이름의 멤버를 만
  들려고 하거나 멤버와 같은 이름의 어트리뷰트를 만들려는 시도는 허용되
  지 않습니다.


고유한 열거형 값 보장하기
=========================

기본적으로, 열거형은 여러 이름을 같은 값에 대한 별칭으로 허용합니다.
이 동작이 바람직하지 않을 때, 다음 데코레이터를 사용하여 각 값이 열거
에서 한 번만 사용되도록 보장할 수 있습니다:

@enum.unique

열거형 용 "class" 데코레이터입니다. 열거형의 "__members__"를 검색하여
별칭을 수집합니다; 발견되면 "ValueError"가 세부 정보와 함께 발생합니다
:

   >>> from enum import Enum, unique
   >>> @unique
   ... class Mistake(Enum):
   ...     ONE = 1
   ...     TWO = 2
   ...     THREE = 3
   ...     FOUR = 3
   ...
   Traceback (most recent call last):
   ...
   ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE


자동 값 사용하기
================

정확한 값이 중요하지 않으면, "auto"를 사용할 수 있습니다:

   >>> from enum import Enum, auto
   >>> class Color(Enum):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> list(Color)
   [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

값은 "_generate_next_value_()"에 의해 선택되는데, 재정의할 수 있습니다
:

   >>> class AutoName(Enum):
   ...     def _generate_next_value_(name, start, count, last_values):
   ...         return name
   ...
   >>> class Ordinal(AutoName):
   ...     NORTH = auto()
   ...     SOUTH = auto()
   ...     EAST = auto()
   ...     WEST = auto()
   ...
   >>> list(Ordinal)
   [<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]

참고:

  기본 "_generate_next_value_()" 메서드의 목표는 제공된 마지막 "int"와
  연속되도록 다음 "int"를 제공하는 것이지만, 이를 수행하는 방법은 구현
  세부 사항이며 변경될 수 있습니다.

참고:

  "_generate_next_value_()" 메서드는 다른 멤버보다 먼저 정의되어야 합
  니다.


이터레이션
==========

열거형 멤버를 이터레이트 해도 별칭은 제공되지 않습니다:

   >>> list(Shape)
   [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]

특수 어트리뷰트 "__members__"는 이름에서 멤버로의 읽기 전용 순서 있는
매핑입니다. 별칭을 포함하여, 열거형에 정의된 모든 이름을 포함합니다:

   >>> for name, member in Shape.__members__.items():
   ...     name, member
   ...
   ('SQUARE', <Shape.SQUARE: 2>)
   ('DIAMOND', <Shape.DIAMOND: 1>)
   ('CIRCLE', <Shape.CIRCLE: 3>)
   ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)

"__members__" 어트리뷰트는 열거형 멤버에 대한 프로그래밍 방식의 자세한
액세스에 사용할 수 있습니다. 예를 들어, 모든 별칭 찾기:

   >>> [name for name, member in Shape.__members__.items() if member.name != name]
   ['ALIAS_FOR_SQUARE']


비교
====

열거형 멤버는 아이덴티티로 비교됩니다:

   >>> Color.RED is Color.RED
   True
   >>> Color.RED is Color.BLUE
   False
   >>> Color.RED is not Color.BLUE
   True

열거형 값 사이의 순서 비교는 지원되지 *않습니다*. 열거형 멤버는 정수가
아닙니다 (그러나 아래의 IntEnum을 참조하십시오):

   >>> Color.RED < Color.BLUE
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: '<' not supported between instances of 'Color' and 'Color'

동등 비교는 정의됩니다:

   >>> Color.BLUE == Color.RED
   False
   >>> Color.BLUE != Color.RED
   True
   >>> Color.BLUE == Color.BLUE
   True

열거형 값이 아닌 값과의 비교는 항상 다르다고 비교됩니다 (다시,
"IntEnum"은 다르게 동작하도록 명시적으로 설계되었습니다, 아래를 참조하
십시오):

   >>> Color.BLUE == 2
   False


열거형의 허용된 멤버와 어트리뷰트
=================================

위의 예제는 열거형 값에 정수를 사용합니다. 정수 사용은 짧고 편리하지만
(함수형 API에서 기본적으로 제공합니다), 엄격하게 강제하지는 않습니다.
대다수의 사용 사례에서, 열거의 실제 값이 무엇인지 신경 쓰지 않습니다.
그러나 값이 *중요*하면, 열거형은 임의의 값을 가질 수 있습니다.

열거형은 파이썬 클래스이며, 평소와 같이 메서드와 특수 메서드를 가질 수
있습니다. 이런 열거형이 있다고 합시다:

   >>> class Mood(Enum):
   ...     FUNKY = 1
   ...     HAPPY = 3
   ...
   ...     def describe(self):
   ...         # self is the member here
   ...         return self.name, self.value
   ...
   ...     def __str__(self):
   ...         return 'my custom str! {0}'.format(self.value)
   ...
   ...     @classmethod
   ...     def favorite_mood(cls):
   ...         # cls here is the enumeration
   ...         return cls.HAPPY
   ...

그러면:

   >>> Mood.favorite_mood()
   <Mood.HAPPY: 3>
   >>> Mood.HAPPY.describe()
   ('HAPPY', 3)
   >>> str(Mood.FUNKY)
   'my custom str! 1'

허용되는 규칙은 다음과 같습니다: 단일 밑줄로 시작하고 끝나는 이름은
enum이 예약하고 있고 사용할 수 없습니다; 열거형 내에 정의된 다른 모든
어트리뷰트는 특수 메서드 ("__str__()", "__add__()" 등), 디스크립터 (메
서드도 디스크립터입니다) 및 "_ignore_"에 나열된 변수 이름을 제외하고
이 열거의 멤버가 됩니다.

참고: 열거형이 "__new__()" 및/또는 "__init__()"를 정의하면 열거형 멤버
에 제공된 모든 값이 해당 메서드에 전달됩니다. 예제는 행성을 참조하십시
오.


제한된 Enum 서브 클래싱
=======================

새로운 "Enum" 클래스에는 하나의 베이스 Enum 클래스, 최대 하나의 구상
데이터형 및 필요한 만큼의 "object" 기반 믹스인 클래스가 있어야 합니다.
이 베이스 클래스의 순서는 다음과 같습니다:

   class EnumName([mix-in, ...,] [data-type,] base-enum):
       pass

또한, 열거형의 서브 클래싱은 열거형이 멤버를 정의하지 않았을 때만 허용
됩니다. 따라서 다음과 같은 것은 금지되어 있습니다:

   >>> class MoreColor(Color):
   ...     PINK = 17
   ...
   Traceback (most recent call last):
   ...
   TypeError: MoreColor: cannot extend enumeration 'Color'

그러나 이것은 허용됩니다:

   >>> class Foo(Enum):
   ...     def some_behavior(self):
   ...         pass
   ...
   >>> class Bar(Foo):
   ...     HAPPY = 1
   ...     SAD = 2
   ...

멤버를 정의하는 열거형의 서브 클래싱을 허용하면 형과 인스턴스의 중요한
불변성을 위반하게 됩니다. 반면에, 열거형 그룹 간에 공통적인 동작을 공
유하도록 허락하는 것은 말이 됩니다. (예는 OrderedEnum을 참조하십시오.)


피클링
======

열거형은 피클링 되거나 역 피클링 될 수 있습니다:

   >>> from test.test_enum import Fruit
   >>> from pickle import dumps, loads
   >>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
   True

피클링에 대한 일반적인 제한 사항이 적용됩니다: 역 피클링은 열거형을 모
듈에서 임포트 할 수 있어야 하므로, 피클 가능한 열거형은 모듈의 최상위
수준에서 정의해야 합니다.

참고:

  피클 프로토콜 버전 4를 사용하면 다른 클래스에 중첩된 열거형을 쉽게
  피클 할 수 있습니다.

열거형 클래스에 "__reduce_ex__()"를 정의하여 Enum 멤버를 피클/역 피클
하는 방법을 수정할 수 있습니다.


함수형 API
==========

"Enum" 클래스는 다음과 같은 함수형 API를 제공하는 콜러블입니다:

   >>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
   >>> Animal
   <enum 'Animal'>
   >>> Animal.ANT
   <Animal.ANT: 1>
   >>> Animal.ANT.value
   1
   >>> list(Animal)
   [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]

이 API의 의미는 "namedtuple"과 유사합니다. "Enum" 호출의 첫 번째 인자
는 열거형의 이름입니다.

두 번째 인자는 열거형 멤버 이름의 *소스*입니다. 공백으로 구분된 이름의
문자열, 이름의 시퀀스, 키/값 쌍 2-튜플의 시퀀스 또는 이름에서 값으로의
매핑(예를 들어, 딕셔너리)일 수 있습니다. 마지막 두 옵션은 임의의 값을
열거형에 할당할 수 있게 합니다; 나머지는 1부터 시작하여 증가하는 정수
를 자동 할당합니다 ( 다른 시작 값을 지정하려면 "start" 매개 변수를 사
용하십시오). "Enum"에서 파생된 새 클래스를 반환합니다. 즉, 위의
"Animal" 대입은 다음과 동등합니다:

   >>> class Animal(Enum):
   ...     ANT = 1
   ...     BEE = 2
   ...     CAT = 3
   ...     DOG = 4
   ...

시작 번호로 "0"이 아니라 "1"을 기본값으로 설정하는 이유는 "0"이 불리언
의미로 "False"이지만 열거형 멤버는 모두 "True"로 평가되기 때문입니다.

함수형 API로 만든 열거형을 피클 하는 것은 까다로울 수 있는데, 프레임
스택 구현 세부 사항을 사용하여 열거형이 만들어지고 있는 모듈을 파악하
고 시도하기 때문입니다 (예를 들어, 별도의 모듈에 있는 유틸리티 함수를
사용하면 실패할 것이고. IronPython이나 Jython에서는 작동하지 않을 수
있습니다). 해결책은 다음과 같이 모듈 이름을 명시적으로 지정하는 것입니
다:

   >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)

경고:

  "module"이 제공되지 않고, Enum이 모듈을 판단할 수 없으면, 새 Enum 멤
  버는 역 피클 되지 않을 것입니다; 에러를 소스에 더 가깝게 유지하기 위
  해, 피클링이 비활성화됩니다.

새로운 피클 프로토콜 4는 일부 상황에서 "__qualname__"이 pickle이 클래
스를 찾을 수 있는 위치로 설정되는 것에 의존합니다. 예를 들어, 클래스가
전역 스코프의 SomeData 클래스 내에 만들어지면:

   >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')

완전한 서명은 다음과 같습니다:

   Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)

value:
   새 Enum 클래스가 자신의 이름으로 기록할 것.

names:
   Enum 멤버. 공백이나 쉼표로 구분된 문자열일 수 있습니다 (지정하지 않
   는 한 값은 1부터 시작합니다):

      'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'

   또는 이름의 이터레이터:

      ['RED', 'GREEN', 'BLUE']

   또는 (이름, 값) 쌍의 이터레이터:

      [('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]

   또는 매핑:

      {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}

module:
   새로운 Enum 클래스를 찾을 수 있는 모듈의 이름.

qualname:
   모듈에서 새로운 Enum 클래스를 찾을 수 있는 곳.

type:
   새로운 Enum 클래스와 혼합할 형.

start:
   이름 만 전달될 때 세기 시작할 숫자.

버전 3.5에서 변경: *start* 매개 변수가 추가되었습니다.


파생된 열거형
=============


IntEnum
-------

제공되는 첫 번째 "Enum"의 변형은 "int"의 서브 클래스이기도 합니다.
"IntEnum"의 멤버는 정수와 비교할 수 있습니다; 확장하여, 다른 정수 열거
형도 서로 비교할 수 있습니다:

   >>> from enum import IntEnum
   >>> class Shape(IntEnum):
   ...     CIRCLE = 1
   ...     SQUARE = 2
   ...
   >>> class Request(IntEnum):
   ...     POST = 1
   ...     GET = 2
   ...
   >>> Shape == 1
   False
   >>> Shape.CIRCLE == 1
   True
   >>> Shape.CIRCLE == Request.POST
   True

그러나, 여전히 표준 "Enum" 열거형과 비교할 수는 없습니다:

   >>> class Shape(IntEnum):
   ...     CIRCLE = 1
   ...     SQUARE = 2
   ...
   >>> class Color(Enum):
   ...     RED = 1
   ...     GREEN = 2
   ...
   >>> Shape.CIRCLE == Color.RED
   False

"IntEnum" 값은 여러분이 기대하는 다른 방식으로 정수처럼 동작합니다:

   >>> int(Shape.CIRCLE)
   1
   >>> ['a', 'b', 'c'][Shape.CIRCLE]
   'b'
   >>> [i for i in range(Shape.SQUARE)]
   [0, 1]


IntFlag
-------

제공된 "Enum"의 다음 변형인 "IntFlag"도 "int"를 기반으로 합니다. 차이
점은, "IntFlag" 멤버는 비트 연산자(&, |, ^, ~)를 사용하여 결합할 수 있
으며 결과는 여전히 "IntFlag" 멤버라는 것입니다. 그러나, 이름에서 알 수
있듯이, "IntFlag" 멤버는 "int"를 서브 클래스하고 "int"가 사용되는 모든
곳에서 사용할 수 있습니다. 비트별 연산 이외의 "IntFlag" 멤버에 대한 모
든 연산은 "IntFlag" 멤버 자격을 잃게 만듭니다.

버전 3.6에 추가.

예제 "IntFlag" 클래스:

   >>> from enum import IntFlag
   >>> class Perm(IntFlag):
   ...     R = 4
   ...     W = 2
   ...     X = 1
   ...
   >>> Perm.R | Perm.W
   <Perm.R|W: 6>
   >>> Perm.R + Perm.W
   6
   >>> RW = Perm.R | Perm.W
   >>> Perm.R in RW
   True

조합의 이름을 지정할 수도 있습니다:

   >>> class Perm(IntFlag):
   ...     R = 4
   ...     W = 2
   ...     X = 1
   ...     RWX = 7
   >>> Perm.RWX
   <Perm.RWX: 7>
   >>> ~Perm.RWX
   <Perm.-8: -8>

"IntFlag"과 "Enum"의 또 다른 중요한 차이점은 아무런 플래그도 설정되지
않으면 (값이 0입니다) 불리언 평가가 "False"가 된다는 것입니다:

   >>> Perm.R & Perm.X
   <Perm.0: 0>
   >>> bool(Perm.R & Perm.X)
   False

"IntFlag" 멤버도 "int"의 서브 클래스이므로 정수와 결합할 수 있습니다:

   >>> Perm.X | 8
   <Perm.8|X: 9>


Flag
----

마지막 변형은 "Flag"입니다. "IntFlag"와 마찬가지로, "Flag" 멤버는 비트
연산자(&, |, ^, ~)를 사용하여 결합할 수 있습니다. "IntFlag"와 달리, 다
른 "Flag" 열거형이나 "int"와 결합하거나 비교할 수 없습니다. 값을 직접
지정할 수는 있지만, "auto"를 값으로 사용하고 "Flag"가 적절한 값을 선택
하도록 하는 것이 좋습니다.

버전 3.6에 추가.

"IntFlag"와 마찬가지로, "Flag" 멤버의 조합이 아무런 플래그도 설정하지
않으면, 불리언 평가는 "False"입니다:

   >>> from enum import Flag, auto
   >>> class Color(Flag):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> Color.RED & Color.GREEN
   <Color.0: 0>
   >>> bool(Color.RED & Color.GREEN)
   False

개별 플래그는 2의 거듭제곱 값(1, 2, 4, 8, ...)을 가져야 하지만, 플래그
의 조합은 그렇지 않습니다:

   >>> class Color(Flag):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...     WHITE = RED | BLUE | GREEN
   ...
   >>> Color.WHITE
   <Color.WHITE: 7>

"플래그 설정 없음" 조건에 이름을 부여해도 불리언 값은 변경되지 않습니
다:

   >>> class Color(Flag):
   ...     BLACK = 0
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> Color.BLACK
   <Color.BLACK: 0>
   >>> bool(Color.BLACK)
   False

참고:

  "IntEnum"과 "IntFlag"는 열거형에 대한 의미론적 약속을 깨뜨리기 때문
  에 (정수와 비교할 수 있어서, 다른 관련되지 않은 열거형으로의 추이성
  (transitivity)으로 인해), 새로운 코드 대부분에는 "Enum"과 "Flag"를
  강력히 권장합니다. "IntEnum"과 "IntFlag"는 "Enum"과 "Flag"가 동작하
  지 않는 경우에만 사용해야 합니다; 예를 들어, 정수 상수가 열거형으로
  대체되거나, 다른 시스템과의 상호 운용성을 위해.


기타
----

"IntEnum"은 "enum" 모듈의 일부이지만, 독립적으로 구현하는 것은 매우 간
단합니다:

   class IntEnum(int, Enum):
       pass

이것은 유사한 파생된 열거형을 정의 할 수 있는 방법을 보여줍니다; 예를
들어 "int" 대신 "str"로 혼합되는 "StrEnum".

몇 가지 규칙:

1. "Enum"을 서브 클래싱 할 때, 위의 "IntEnum" 예제에서처럼, 혼합(mix-
   in)형은 베이스 시퀀스에서 "Enum" 앞에 나타나야 합니다.

2. "Enum"은 모든 형의 멤버를 가질 수 있지만, 일단 추가 형을 혼합하면,
   모든 멤버는 해당 형의 값을 가져야 합니다, 예를 들어 위의 "int". 이
   제한은 메서드만 추가할 뿐 다른 형을 지정하지 않는 믹스인에는 적용되
   지 않습니다.

3. 다른 데이터형이 혼합될 때, "value" 어트리뷰트는 열거형 멤버 자체와
   *같지 않지*만, 동등하고 같다고 비교됩니다.

4. %-스타일 포매팅: *%s* 와 *%r* 은 각각 "Enum" 클래스의 "__str__()"과
   "__repr__()"을 호출합니다; 다른 코드(가령 IntEnum의 경우 *%i* 나
   *%h*)는 열거형 멤버를 혼합형으로 취급합니다.

5. 포맷 문자열 리터럴, "str.format()" 및 "format()"은 혼합형의
   "__format__()"을 사용합니다. 하지만, 서브 클래스에서 "__str__()"이
   나 "__format__()"이 재정의되면, 재정의된 메서드나 "Enum" 메소드가
   사용됩니다. "Enum" 클래스의 "__str__()"과 "__repr__()" 메서드의 사
   용을 강제하려면 !s 과 !r 포맷 코드를 사용하십시오.


"__new__()"나 "__init__()"를 사용할 때
======================================

"Enum" 멤버의 실제 값을 사용자 정의하려면 "__new__()"를 사용해야 합니
다. 다른 수정은 "__new__()"나 "__init__()"를 사용할 수 있지만,
"__init__()"가 바람직합니다.

예를 들어, 여러 항목을 생성자에 전달하고 싶지만, 그중 하나만 값이 되도
록 하려면 다음과 같이 합니다:

   >>> class Coordinate(bytes, Enum):
   ...     """
   ...     Coordinate with binary codes that can be indexed by the int code.
   ...     """
   ...     def __new__(cls, value, label, unit):
   ...         obj = bytes.__new__(cls, [value])
   ...         obj._value_ = value
   ...         obj.label = label
   ...         obj.unit = unit
   ...         return obj
   ...     PX = (0, 'P.X', 'km')
   ...     PY = (1, 'P.Y', 'km')
   ...     VX = (2, 'V.X', 'km/s')
   ...     VY = (3, 'V.Y', 'km/s')
   ...

   >>> print(Coordinate['PY'])
   Coordinate.PY

   >>> print(Coordinate(3))
   Coordinate.VY


흥미로운 예
===========

"Enum", "IntEnum", "IntFlag" 및 "Flag"는 대부분의 사용 사례를 포괄할
것으로 예상되지만, 모든 사용 사례를 포괄할 수는 없습니다. 다음은 직접
혹은 자신의 것을 만드는 예제로 사용할 수 있는 여러 유형의 열거형에 대
한 조리법입니다.


값 생략하기
-----------

많은 사용 사례에서 열거형의 실제 값이 무엇인지 신경 쓰지 않습니다. 이
런 유형의 간단한 열거형을 정의하는 몇 가지 방법이 있습니다:

* "auto"의 인스턴스를 값으로 사용합니다

* "object" 인스턴스를 값으로 사용합니다

* 설명 문자열을 값으로 사용합니다

* 튜플을 값으로 사용하고 사용자 정의 "__new__()"를 사용하여 튜플을
  "int" 값으로 대체합니다

이러한 방법의 하나를 사용하는 것은 사용자에게 이러한 값이 중요하지 않
다고 알리고, 나머지 멤버의 번호를 다시 매길 필요 없이 멤버를 추가, 제
거 또는 재정렬 할 수 있도록 합니다.

어떤 방법을 선택하든, (중요하지 않은) 값을 숨기는 "repr()"을 제공해야
합니다:

   >>> class NoValue(Enum):
   ...     def __repr__(self):
   ...         return '<%s.%s>' % (self.__class__.__name__, self.name)
   ...


"auto" 사용하기
~~~~~~~~~~~~~~~

"auto"를 사용하면 이렇게 됩니다:

   >>> class Color(NoValue):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> Color.GREEN
   <Color.GREEN>


"object" 사용하기
~~~~~~~~~~~~~~~~~

"object"를 사용하면 이렇게 됩니다:

   >>> class Color(NoValue):
   ...     RED = object()
   ...     GREEN = object()
   ...     BLUE = object()
   ...
   >>> Color.GREEN
   <Color.GREEN>


설명 문자열 사용하기
~~~~~~~~~~~~~~~~~~~~

문자열을 값으로 사용하면 이렇게 됩니다:

   >>> class Color(NoValue):
   ...     RED = 'stop'
   ...     GREEN = 'go'
   ...     BLUE = 'too fast!'
   ...
   >>> Color.GREEN
   <Color.GREEN>
   >>> Color.GREEN.value
   'go'


사용자 정의 "__new__()" 사용하기
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

자동 번호 매기기 "__new__()"를 사용하면 이렇게 됩니다:

   >>> class AutoNumber(NoValue):
   ...     def __new__(cls):
   ...         value = len(cls.__members__) + 1
   ...         obj = object.__new__(cls)
   ...         obj._value_ = value
   ...         return obj
   ...
   >>> class Color(AutoNumber):
   ...     RED = ()
   ...     GREEN = ()
   ...     BLUE = ()
   ...
   >>> Color.GREEN
   <Color.GREEN>
   >>> Color.GREEN.value
   2

더 범용의 "AutoNumber"를 만들려면, 서명에 "*args"를 추가합니다:

   >>> class AutoNumber(NoValue):
   ...     def __new__(cls, *args):      # this is the only change from above
   ...         value = len(cls.__members__) + 1
   ...         obj = object.__new__(cls)
   ...         obj._value_ = value
   ...         return obj
   ...

그런 다음 "AutoNumber"에서 상속할 때 추가 인자를 처리하기 위해 자체
"__init__"를 작성할 수 있습니다:

   >>> class Swatch(AutoNumber):
   ...     def __init__(self, pantone='unknown'):
   ...         self.pantone = pantone
   ...     AUBURN = '3497'
   ...     SEA_GREEN = '1246'
   ...     BLEACHED_CORAL = () # New color, no Pantone code yet!
   ...
   >>> Swatch.SEA_GREEN
   <Swatch.SEA_GREEN>
   >>> Swatch.SEA_GREEN.pantone
   '1246'
   >>> Swatch.BLEACHED_CORAL.pantone
   'unknown'

참고:

  정의되면, "__new__()" 메서드는 Enum 멤버 생성 중에 사용됩니다; 그런
  다음 Enum의 "__new__()"로 대체되는데, 이것이 클래스 생성 후에 기존
  멤버를 조회하기 위해 사용됩니다.


OrderedEnum
-----------

"IntEnum"에 기반하지 않기 때문에 일반적인 "Enum" 불변성(invariants) (
가령 다른 열거형과 비교할 수 없다는 성질) 을 유지하는 순서 있는 열거형
:

   >>> class OrderedEnum(Enum):
   ...     def __ge__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value >= other.value
   ...         return NotImplemented
   ...     def __gt__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value > other.value
   ...         return NotImplemented
   ...     def __le__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value <= other.value
   ...         return NotImplemented
   ...     def __lt__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value < other.value
   ...         return NotImplemented
   ...
   >>> class Grade(OrderedEnum):
   ...     A = 5
   ...     B = 4
   ...     C = 3
   ...     D = 2
   ...     F = 1
   ...
   >>> Grade.C < Grade.A
   True


DuplicateFreeEnum
-----------------

중복된 멤버 이름이 발견되면 별칭을 만드는 대신 에러를 발생시킵니다:

   >>> class DuplicateFreeEnum(Enum):
   ...     def __init__(self, *args):
   ...         cls = self.__class__
   ...         if any(self.value == e.value for e in cls):
   ...             a = self.name
   ...             e = cls(self.value).name
   ...             raise ValueError(
   ...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
   ...                 % (a, e))
   ...
   >>> class Color(DuplicateFreeEnum):
   ...     RED = 1
   ...     GREEN = 2
   ...     BLUE = 3
   ...     GRENE = 2
   ...
   Traceback (most recent call last):
   ...
   ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'

참고:

  이것은 별칭을 허락하지 않는 것뿐 아니라 Enum을 서브 클래싱하여 다른
  동작을 추가하거나 변경하는 유용한 예입니다. 원하는 변경이 오직 별칭
  을 허용하지 않는 것이면, "unique()" 데코레이터를 대신 사용할 수 있습
  니다.


행성
----

"__new__()"나 "__init__()"가 정의되면 열거형 멤버의 값이 해당 메서드로
전달됩니다:

   >>> class Planet(Enum):
   ...     MERCURY = (3.303e+23, 2.4397e6)
   ...     VENUS   = (4.869e+24, 6.0518e6)
   ...     EARTH   = (5.976e+24, 6.37814e6)
   ...     MARS    = (6.421e+23, 3.3972e6)
   ...     JUPITER = (1.9e+27,   7.1492e7)
   ...     SATURN  = (5.688e+26, 6.0268e7)
   ...     URANUS  = (8.686e+25, 2.5559e7)
   ...     NEPTUNE = (1.024e+26, 2.4746e7)
   ...     def __init__(self, mass, radius):
   ...         self.mass = mass       # in kilograms
   ...         self.radius = radius   # in meters
   ...     @property
   ...     def surface_gravity(self):
   ...         # universal gravitational constant  (m3 kg-1 s-2)
   ...         G = 6.67300E-11
   ...         return G * self.mass / (self.radius * self.radius)
   ...
   >>> Planet.EARTH.value
   (5.976e+24, 6378140.0)
   >>> Planet.EARTH.surface_gravity
   9.802652743337129


TimePeriod
----------

"_ignore_" 어트리뷰트의 사용을 보여주는 예:

   >>> from datetime import timedelta
   >>> class Period(timedelta, Enum):
   ...     "different lengths of time"
   ...     _ignore_ = 'Period i'
   ...     Period = vars()
   ...     for i in range(367):
   ...         Period['day_%d' % i] = i
   ...
   >>> list(Period)[:2]
   [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
   >>> list(Period)[-2:]
   [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]


열거형은 어떻게 다릅니까?
=========================

열거형은 파생된 Enum 클래스와 그들의 인스턴스(멤버)의 여러 측면에 영향
을 주는 사용자 정의 메타 클래스를 갖습니다.


열거형 클래스
-------------

"EnumMeta" 메타 클래스는 *list(Color)*나 *some_enum_var in Color*와 같
은 일반적인 클래스에서 실패하는 연산을 "Enum" 클래스로 할 수 있도록 하
는 "__contains__()", "__dir__()", "__iter__()" 및 기타 메서드를 제공합
니다. "EnumMeta"는 최종 "Enum" 클래스의 다양한 다른 메서드(가령
"__new__()", "__getnewargs__()", "__str__()" 및 "__repr__()")가 올바른
지 확인합니다.


열거형 멤버 (일명 인스턴스)
---------------------------

Enum 멤버에 대한 가장 흥미로운 점은 싱글톤이라는 것입니다. "EnumMeta"
는 "Enum" 클래스 자체를 만드는 동안 멤버를 모두 만든 다음, 사용자 정의
"__new__()"를 넣어서 기존 멤버 인스턴스만 반환하여 더는 새 인스턴스가
만들어지지 않도록 합니다.


세부 사항
---------


지원되는 "__dunder__" 이름
~~~~~~~~~~~~~~~~~~~~~~~~~~

"__members__"는 "member_name":"member" 항목의 읽기 전용 순서 있는 매핑
입니다. 클래스에서만 이용할 수 있습니다.

지정된다면, "__new__()"는 열거형 멤버를 만들고 반환해야 합니다; 멤버의
"_value_"를 적절하게 설정하는 것도 좋습니다. 일단 모든 멤버가 만들어지
면 더는 사용되지 않습니다.


지원되는 "_sunder_" 이름
~~~~~~~~~~~~~~~~~~~~~~~~

* "_name_" -- 멤버의 이름

* "_value_" -- 멤버의 값; "__new__"에서 설정/수정할 수 있습니다

* "_missing_" -- 값을 찾을 수 없을 때 사용되는 조회 함수; 재정의할 수
  있습니다

* "_ignore_" -- 멤버로 변환되지 않고 최종 클래스에서 제거될 "list"나
  "str" 형의 이름 목록

* "_order_" -- 파이썬 2/3 코드에서 멤버 순서의 일관성을 유지하기 위해
  사용됩니다 (클래스 생성 중 제거되는 클래스 어트리뷰트)

* "_generate_next_value_" -- 열거형 멤버에 대한 적절한 값을 얻기 위해
  함수형 API와 "auto"에서 사용합니다; 재정의할 수 있습니다

버전 3.6에 추가: "_missing_", "_order_", "_generate_next_value_"

버전 3.7에 추가: "_ignore_"

파이썬 2 / 파이썬 3 코드를 동기화 상태로 유지하기 위해 "_order_" 어트
리뷰트를 제공 할 수 있습니다. 열거형의 실제 순서와 비교하여 확인되며
일치하지 않으면 에러가 발생합니다:

   >>> class Color(Enum):
   ...     _order_ = 'RED GREEN BLUE'
   ...     RED = 1
   ...     BLUE = 3
   ...     GREEN = 2
   ...
   Traceback (most recent call last):
   ...
   TypeError: member order does not match _order_

참고:

  파이썬 2 코드에서는 정의 순서가 기록될 수 있기 전에 손실되기 때문에
  "_order_" 어트리뷰트가 필요합니다.


_Private__names
~~~~~~~~~~~~~~~

Private names will be normal attributes in Python 3.11 instead of
either an error or a member (depending on if the name ends with an
underscore). Using these names in 3.10 will issue a
"DeprecationWarning".


"Enum" 멤버 형
~~~~~~~~~~~~~~

"Enum" 멤버는 "Enum" 클래스의 인스턴스이며, 일반적으로
"EnumClass.member"로 액세스 됩니다. 특정 상황에서는
"EnumClass.member.member"로 액세스 할 수 있지만, 조회가 실패하거나 더
나쁜 경우 찾고 있는 "Enum" 멤버 이외의 것을 반환할 수 있기 때문에 이
작업을 수행해서는 안 됩니다 (이것은 멤버에 모두 대문자로 구성된 이름을
사용하는 또 하나의 이유입니다):

   >>> class FieldTypes(Enum):
   ...     name = 0
   ...     value = 1
   ...     size = 2
   ...
   >>> FieldTypes.value.size
   <FieldTypes.size: 2>
   >>> FieldTypes.size.value
   2

참고:

  This behavior is deprecated and will be removed in 3.11.

버전 3.5에서 변경.


"Enum" 클래스와 멤버의 불리언 값
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

비 "Enum" 형(가령 "int", "str" 등)과 혼합된 "Enum" 멤버는 혼합형의 규
칙에 따라 평가됩니다; 그렇지 않으면, 모든 멤버가 "True"로 평가됩니다.
여러분 자신의 Enum의 불리언 평가를 멤버의 값에 따르게 하려면 클래스에
다음을 추가하십시오:

   def __bool__(self):
       return bool(self.value)

"Enum" 클래스는 항상 "True"로 평가됩니다.


메서드가 있는 "Enum" 클래스
~~~~~~~~~~~~~~~~~~~~~~~~~~~

"Enum" 서브 클래스에 위의 Planet 클래스처럼 추가 메서드를 제공하면, 해
당 메서드는 멤버의 "dir()"에 표시되지만, 클래스에서는 표시되지 않습니
다:

   >>> dir(Planet)
   ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
   >>> dir(Planet.EARTH)
   ['__class__', '__doc__', '__module__', 'mass', 'name', 'radius', 'surface_gravity', 'value']


"Flag" 멤버를 결합하기
~~~~~~~~~~~~~~~~~~~~~~

Flag 멤버 조합의 이름이 지정되지 않으면, "repr()"은 모든 이름 지정된
플래그와 값에 있는 플래그의 모든 이름 지정된 조합을 포함합니다:

   >>> class Color(Flag):
   ...     RED = auto()
   ...     GREEN = auto()
   ...     BLUE = auto()
   ...     MAGENTA = RED | BLUE
   ...     YELLOW = RED | GREEN
   ...     CYAN = GREEN | BLUE
   ...
   >>> Color(3)  # named combination
   <Color.YELLOW: 3>
   >>> Color(7)      # not named combination
   <Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>

참고:

  In 3.11 unnamed combinations of flags will only produce the
  canonical flag members (aka single-value flags).  So "Color(7)" will
  produce something like "<Color.BLUE|GREEN|RED: 7>".
