python :: enum

PHYYOU·2020년 11월 28일
1

python

목록 보기
1/2

enum의 정의

관련이 있는 상수들의 집합입니다. 자바에서는 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>]

사용

Attribution(속성)

일단 이렇게 선언하고 enum 타입의 상수 인스턴스는 기본적으로 이름(name)값(value)을 속성을 가진다.

ModelName
# <enum 'ModelName'>
ModelName.alexnet
# <ModelName.alexnet: 'alexnet'>
ModelName.alexnet.name
# 'alexnet'
ModelName.alexnet.value
# 'alexnet'

for문으로 사용하자

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 mixin

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 확장

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 공식 문서

profile
박효영

0개의 댓글