Python Enum 사용하기

햄도·2021년 1월 8일
0

일을 하다보면 숫자로 된 코드값을 이용해 값을 구분하는 경우가 많은데, 숫자 코드값을 이용하면 텍스트로 된 데이터를 숫자 두 자리 정도로 압축하기 때문에 데이터가 줄어들고 쿼리 등에서 이용할 때 오타의 위험도 줄어든다. 하지만 아래의 이유들로 인해 코드값을 직접 소스에 사용하는 것이 싫었다.

  1. 코드값만을 보고 로직을 파악하기 힘들다. 각 코드값이 의미하는 내용을 다시 찾아보고, 나중에 또 볼 때에도 코드값을 잊어버리면 또 찾아봐야 한다.
  2. 특정 케이스에 사용되는 여러 코드값의 묶음이 있는 경우 코드값을 일일이 조합하기 매우 불편하다.

이때문에 여러 코드값의 조합은 다른 분이 구현해두신 Enum으로 교체하기로 했다. Enum도 결국은 코드값이 변경되거나 추가되었을 때 관리해주어야 하는 유지보수 대상이기 때문에, 빈번하게 수정된다면 불편할 것 같다. 하지만 자주 수정되는 값이라면 애초에 코드값으로 등록하지도 않겠지..

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

기본적으로는 위와 같은 형태로 사용한다.

한 가지 헷갈렸던 건, 구현되어있는 Enum 클래스의 __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):
        # 중력 상수  (m3 kg-1 s-2)
        G = 6.67300E-11
        return G * self.mass / (self.radius * self.radius)

이 부분의 설명이 '__new__()__init__()가 정의되면 열거형 멤버의 값이 해당 메서드로 전달됩니다' 라고 되어있었는데 이 말이 무슨 의미인지 한 번에 와닿지 않았는데, 아래 코드를 보고 이해할 수 있었다.

>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129

__init__() 을 정의하면, 정의된 매개변수 순서대로 각 값에 이름이 붙고, 이것을 외부에서 호출하거나 내부 함수를 구현할 때 사용할 수 있다.

from enum import Enum

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):
        self.mass = mass       # in kilograms
#         self.radius = radius   # in meters
    @property
    def surface_gravity(self):
        # 중력 상수  (m3 kg-1 s-2)
        G = 6.67300E-11
        return G * self.mass / (self.radius * self.radius)

TypeErrorTraceback (most recent call last)
<ipython-input-10-0ff37f5b61bf> in <module>
      1 from enum import Enum
      2 
----> 3 class Planet(Enum):
      4     MERCURY = (3.303e+23, 2.4397e6)
      5     VENUS   = (4.869e+24, 6.0518e6)

/usr/local/lib/python3.8/enum.py in __new__(metacls, cls, bases, classdict)
    219             enum_member._name_ = member_name
    220             enum_member.__objclass__ = enum_class
--> 221             enum_member.__init__(*args)
    222             # If another member with the same value was already defined, the
    223             # new member becomes an alias to the existing one.

TypeError: __init__() takes 2 positional arguments but 3 were given

__init__() 의 인자 수를 위에 정의된 상수들과 맞춰주지 않으면 위와 같은 에러가 발생한다. 열거형 멤버의 값이 해당 메서드(__init__() )로 전달된다는 것이 이런 의미였다. 생성자를 만들어주는 경우 정의한 상수들은 모두 __init__() 메서드로 전달되고, 하나하나가 각 값을 속성으로 가진 Planet 클래스의 객체가 된다.

참고

profile
developer hamdoe

0개의 댓글