Profile picture

[Python] 파이썬 enum 타입

JaehyoJJAng2023년 06월 06일

◾️ enum

enum은 일반적으로 서로 관련이 있는 여러 개의 상수 집합을 정의할 때 사용된다.

enum 클래스 사용 시 인스턴스의 종류를 제한할 수 있어 견고한 프로그램을 구현하는데 많은 도움이 될 수 있다.


▪️ 클래스 타입 정의

간단한 예시로, 프로그래밍 언어(Python,JavaScript,Java)을 나타내는 enum 클래스를 작성해보자.

enum 내장 모듈로부터 불러온 Enum 클래스를 확장하여 Languages 타입을 만들어보자.

from enum import Enum

class Languages(Enum):
    PYTHON = 1
    JAVASCRIPT = 2
    JAVA = 3

enum 타입의 상수 인스턴스는 기본적으로 이름(name)과 값(value)을 속성으로 가진다.

>>> Languages.PYTHON
<Languages.PYTHON: 1>

>>> Languages.PYTHON.name
'PYTHON'

>>> Languages.PYTHON.value
1

enum 타입은 순회가 가능하기 때문에 for문으로 모든 상수를 쉽게 확인할 수 있다.

>>> for language in Languages:
...     print(language)
...
Languages.PYTHON
Languages.JAVASCRIPT
Languages.JAVA

▪️ 함수형 타입 정의

자주 쓰이는 방법은 아니지만 Enum 클래스를 확장하는 대신에 일반 함수처럼 호출을 해서 enum 타입을 정의할 수도 있다.

from enum import Enum

Languages = Enum('Languages','PYTHON JAVASCRIPT JAVA')
list(Languages)

▪️ 값 자동 할당

enum을 사용할 때에 값(value)이 무엇인지는 크게 중요하지 않은 경우가 있을 수 있다.

이럴 때는 enum 모듈의 auto() helper 함수를 사용하면, 첫번째 상수에 1, 두번째 상수에 2, 이렇게 1씩 증가시키면서 모든 상수에 유일한 숫자를 값으로 할당시켜준다.

from enum import Enum, auto

class Languages(Enum):
    PYTHON = auto()
    JAVASCRIPT = auto()
    JAVA = auto()

list(Languages)
>>> list(Languages)
[<Languages.PYTHON: 1>, <Languages.JAVASCRIPT: 2>, <Languages.JAVA: 3>]

auto() 함수를 사용하면 기존 상수에 어떤 숫자를 할당했었는지 알아야 할 필요가 없고, 새로운 상수를 추가할 수 있다는 장점이 있다.

뿐만 아니라, Enum 클래스의 _generate_next_value_() 메서드를 오버라이드하면 숫자가 아닌 다른 값으로 자동 할당할 수 있다.

예를 들어, 상수의 이름과 동일한 문자열을 상수의 값으로 자동 할당이 가능하다.

from enum import Enum, auto

class Languages(Enum):
    def _generate_next_value_(name,start,count,value):
        return name
    PYTHON = auto()
    JAVASCRIPT = auto()
    JAVA = auto()

list(Languages)
>>> list(Languages)
[<Languages.PYTHON: 'PYTHON'>, <Languages.JAVASCRIPT: 'JAVASCRIPT'>, <Languages.JAVA: 'JAVA'>]

▪️ enum mixin

enum 타입을 사용할 때 한 가지 불편할 수 있는 점은 상수의 이름이나 값에 접근할 때 name이나 value 속성을 사용해야 한다는 점이다.

>>> Languages.PYTHON.name == 'PYTHON'
True

>>> Languages.JAVASCRIPT.name == 'JAVASCRIPT'
True

>>> Languages.JAVA.name == 'JAVA'
True

왜냐하면 모든 상수는 결국 해당 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 Languages(StrEnum):
    PYTHON = auto()
    JAVASCRIPT = auto()
    JAVA = auto()

이제 Languages 타입이 담고 있는 상수는 완벽하게 문자열로 취급하기 때문에 조금 더 편하게 사용이 가능하다.

class Languages(StrEnum):
    PYTHON = auto()
    JAVASCRIPT = auto()
    JAVA = auto()
>>> Languages.PYTHON == 'PYTHON'
True

>>> isinstance(Languages.PYTHON, str)
True

▪️ Enum 확장

Enum 클래스는 다른 일반 클래스처럼 다양하게 확장하여 사용이 가능하다.

from enum import Enum

class Languages(Enum):
    PYTHON = ("PYTHON", "Good")
    JAVASCRIPT = ("JAVASCRIPT", "Goood")
    JAVA = ("JAVA", "Gooood")

    def __init__(self,title: str, description: str) -> None:
        self.title = title
        self.description = description
    
    @classmethod
    def get_most_popular(cls):
        return cls.PYTHON

Loading script...