관련이 있는 상수들의 집합입니다. 자바에서는 final로 String과 같은 문자열이나 숫자들을 나타내는 기본 자료형의 값을 고정할 수 있습니다. 이렇게 고정된 값을 상수라고 합니다. 영어로는 constant입니다. 어떤 클래스가 상수만으로 작성되어 있으면 반드시 class로 선언할 필요는 없습니다. 이럴 때 class로 선언된 부분에 enum이라고 선언하면 이 객체는 상수의 집합이다. 라는 것을 명시적으로 나타냅니다. enum은 enumeration이라는 셈, 계산, 열거, 목록이라는 영어단어의 앞부분만 따서 만든 예약어입니다.
나는 여태까지 다른언어나 파이썬에서 딱히 enum을 쓴 때가 별로 없었던 것 같았다. 기껏해야 남에 코드 긁었을 때 enum 이구나 하고 했던 것들이 기억난다.
그러나 이제 enum 클래스에 알아야 할 때가 왔는데 fastapi의 공식 문서를 읽던 도중 pydantic으로 모델을 만들 때 django의 choice fields와 같이 선택하는 필드의 경우 enum으로 나타내었기 때문이다.
위의 정의를 본다면, 그냥 상수 여러개의 집합이라 다양한 상수를 표현하기 쉽게 할려고 하는 것이라 할 수 있다.
파이썬 3.4 버전부터 사용가능한 enum은 클래스와 함수로 정의할 수 있는데 대부분 클래스로 정의하게 된다.
from enum import Enum
# ...
class ModelName(str, Enum):
alexnet = "alexnet"
resnet = "resnet"
lenet = "lenet"
이건 앞서 말했듯이 fastapi 공식 문서에 나오는 enum 인데 클래스를 선얼할 때 str은 지금 생각할 필요는 없다. 그 뒤에 Enum으로 선언된 것이 보이는가?
자주 쓰이는 방법은 아니지만 Enum 클래스를 확장하는 대신에 일반 함수처럼 호출을 해서 enum 타입을 정의할 수도 있다.
Skill = Enum("Skill", "HTML CSS JS")
list(Skill)
# [<Skill.HTML: 1>, <Skill.CSS: 2>, <Skill.JS: 3>]
일단 이렇게 선언하고 enum 타입의 상수 인스턴스는 기본적으로 이름(name)
과 값(value)
을 속성을 가진다.
ModelName
# <enum 'ModelName'>
ModelName.alexnet
# <ModelName.alexnet: 'alexnet'>
ModelName.alexnet.name
# 'alexnet'
ModelName.alexnet.value
# 'alexnet'
enum 타입은 순회가 가능하기 때문에 for 문으로 모든 상수를 쉽게 확인할 수 있다.
for Model in ModelName:
print(f"{Model.name}-{Model.value}")
# alexnet-alexnet
# resnet-resnet
# lenet-lenet
enum을 사용할 때, 대부분 값(value)
이 무언인지는 크게 중요하지 않을때가 많다. 이럴 때는 enum 모듈
의 auto() helper 함수
를 사용하면, 첫번째 상수에 1, 두번째 상수에 2, 이렇게 1씩 증가시키면서 모든 상수에 유일한 숫자를 값으로 할당해준다.
from enum import Enum, auto
class Skill(Enum):
HTML = auto()
CSS = auto()
JS = auto()
list(Skill)
# [<Skill.HTML: 1>, <Skill.CSS: 2>, <Skill.JS: 3>]
enum 타입을 사용할 때 한 가지 불편할 것 같은 점은 상수의 이름이나 값에 접근할 때 name
이나 value
속성을 사용해야 한다는 것이다.
Skill.HTML.name == 'HTML'
# True
Skill.HTML.value == 1
# True
Skill.HTML == 'HTML'
# False
type(Skill.HTML)
# <enum 'Skill'>
왜냐하면 모든 상수는 결국 해당 enum 타입의 인스턴스이기 때문입니다. 하지만 enum 타입을 사용해서 코딩을 하다보면, 매번 name
이나 value
를 사용하는 것이 귀찮고 까먹기도 쉽다.
이럴 때는 enum mixin(믹스인)
기법을 활용하여 str
을 확장하는 enum
클래스를 작성한다.
class StrEnum(str, Enum):
def _generate_next_value_(name, start, count, last_values):
return name
def __repr__(self):
return self.name
def __str__(self):
return self.name
그 다음, 이 클래스를 확장하여 enum 클래스를 정의하면 된다.
class Skill(StrEnum):
HTML = auto()
CSS = auto()
JS = auto()
이제 Skill 타입이 담고 있는 상수는 완벽하게 문자열로 취급기 때문에 좀 더 편하게 사용할 수 있다.
Skill.HTML == 'HTML'
# True
isinstance(Skill.HTML, str)
# True
Enum 클래스는 다른 일반 클래스처럼 다양하게 확장해서 활용할 수 있다.
from enum import Enum
class Skill(Enum):
HTML = ("HTML", "Hypertext Markup Language")
CSS = ("CSS", "Cascading Style Sheets")
JS = ("JS", "JavaScript")
def __init__(self, title, description):
self.title = title
self.description = description
@classmethod
def get_most_popular(cls):
return cls.JS
def lower_title(self):
return self.title.lower()
>>> Skill.HTML.value
('HTML', 'Hypertext Markup Language')
>>> Skill.HTML.title
'HTML'
>>> Skill.HTML.description
'Hypertext Markup Language'
>>> Skill.get_most_popular()
<Skill.JS: ('JS', 'JavaScript')>
>>> Skill.CSS.lower_title()
'css'
이상으로 파이썬에서 enum 내장 모듈을 이용해서 enum 타입을 정의하고 사용하는 방법에 대해서 알아보았다. 파이썬의 enum 내장 모듈에 대한 자세한 내용은 아래 파이썬 공식 레퍼런스를 참고하자!
enum — Support for enumerations: https://docs.python.org/3/library/enum.html
https://www.daleseo.com/python-enum/ enum 설명 글
https://fastapi.tiangolo.com/ko/tutorial/path-params/ fastapi 공식 문서