Python 강좌 : 제 29강 - 열거형
열거(enumerate)
열거 함수(enumerate)는 반복 가능한(iterable) 객체를 받아 색인 값과 요소 값을 쌍으로 반환하는 enumerate 객체를 생성하는 내장 함수입니다.
색인 값을 활용하기 위해 range(len(n))의 형태로 사용하지 않고 enumerate()로 활용이 가능합니다.
Python에서 열거형은 두 가지 의미로 사용됩니다.
하나는 반복하면서 색인 값을 함께 반환하는 열거 함수(enumerate)이며, 다른 하나는 이름이 붙은 상수의 집합을 정의하는 열거형 클래스(enum.Enum)입니다.
두 기능은 이름이 비슷하지만 용도가 전혀 다릅니다.
enumerate는 반복문에서 “몇 번째 요소인지”를 함께 얻기 위한 도구이고, Enum은 1, "red"처럼 의미를 알기 어려운 값 대신 이름이 붙은 상수를 정의하기 위한 클래스입니다.
이번 강좌에서는 enumerate로 색인과 요소를 함께 반복하는 방법을 먼저 다루고, 이어서 Enum과 그 변형인 IntEnum, StrEnum, Flag, 그리고 열거형을 검증하고 멤버를 지정하는 방법을 다룹니다.
반복문 적용
제 15강에서 다룬 for 문은 요소를 하나씩 꺼내 줄 뿐, 그 요소가 몇 번째 요소인지는 알려 주지 않습니다.
순서를 함께 출력하거나, 특정 위치의 요소를 수정해야 할 때는 색인 값이 필요합니다.
data = ["Python", "076923", "YUNDAEHEE"]
for i in range(len(data)):
print(i, data[i])- 결과
- 0 Python
1 076923
2 YUNDAEHEE
enumerate를 사용하지 않는다면, range(len(data))로 색인 값을 만들고 data[i]로 요소에 접근해야 합니다.
이 방식은 동작은 하지만 data를 두 번 작성해야 하고, 요소를 얻기 위해 매번 색인으로 접근해야 하므로 코드의 의도가 잘 드러나지 않습니다.
또한, 집합이나 파일 객체처럼 색인으로 접근할 수 없는 반복 가능한 객체에는 사용할 수 없습니다.
data = ["Python", "076923", "YUNDAEHEE"]
for i, datum in enumerate(data):
print(i, datum)- 결과
- 0 Python
1 076923
2 YUNDAEHEE
for 색인 값, 요소 값 in enumerate(반복 가능한 객체):의 형태로 구성됩니다.
반복문을 for i in range(len(data))로 구성하지 않고 enumerate로 반복문을 구성합니다.
색인 값이 앞에 오며, 요소 값이 뒤에 오는 구조가 됩니다.
enumerate는 반복할 때마다 (0, "Python"), (1, "076923")처럼 색인과 요소를 묶은 튜플을 반환하며, for i, datum이 이 튜플을 두 변수로 나누어 받습니다.
결과는 range(len(data))를 사용한 예제와 같지만, 코드가 더 짧고 “색인과 요소를 함께 반복한다”는 의도가 명확합니다.
data = ["Python", "076923", "YUNDAEHEE"]
for i, datum in enumerate(data, start=1):
print(i, datum)
print(enumerate(data))
print(list(enumerate(data)))- 결과
- 1 Python
2 076923
3 YUNDAEHEE
<enumerate object at 0x000001BD190C53F0>
[(0, ‘Python’), (1, ‘076923’), (2, ‘YUNDAEHEE’)]
enumerate(반복 가능한 객체, start=시작 값)으로 색인 값의 시작 값을 설정할 수 있습니다.
start의 기본값은 0입니다.
start=1은 화면에 “1번, 2번, 3번”처럼 사람이 읽는 번호를 출력할 때 유용합니다. 단, start는 출력되는 숫자만 바꿀 뿐, 반복이 시작되는 요소를 바꾸지는 않습니다. 첫 번째 요소부터 반복하며 번호만 1부터 매겨집니다.
enumerate 함수는 목록이 아닌 enumerate 객체(반복자)를 반환하므로, 값을 확인하려면 list() 등으로 변환합니다.
enumerate 객체는 (색인 값, 요소 값) 형태의 튜플을 하나씩 반환합니다.
- Tip :
enumerate객체의 메모리 주소(0x...)는 실행할 때마다 달라집니다.
data = ["Python", "076923", "YUNDAEHEE"]
items = enumerate(data)
print(list(items))
print(list(items))- 결과
- [(0, ‘Python’), (1, ‘076923’), (2, ‘YUNDAEHEE’)]
[]
enumerate 객체는 반복자(iterator)이므로, 값을 한 번 모두 꺼내면 다시 사용할 수 없습니다.
첫 번째 list(items)에서 모든 값을 꺼냈기 때문에, 두 번째 list(items)는 빈 목록이 됩니다.
enumerate는 요소를 미리 목록으로 만들어 두지 않고 요청할 때마다 하나씩 만들어 반환하기 때문에 메모리를 적게 사용하지만, 이런 특성을 기억해야 합니다. 다시 반복하려면 enumerate(data)를 새로 호출합니다.
for i, char in enumerate("ABC"):
print(i, char)
scores = {"kor": 90, "eng": 85}
for i, (key, value) in enumerate(scores.items()):
print(i, key, value)- 결과
- 0 A
1 B
2 C
0 kor 90
1 eng 85
enumerate는 목록뿐만 아니라 모든 반복 가능한 객체에 사용할 수 있습니다.
문자열은 문자 하나씩, 사전의 items()는 (키, 값) 튜플 하나씩 반환하므로, 색인과 함께 반복할 수 있습니다.
사전의 경우 enumerate가 (색인, (키, 값)) 형태를 반환하므로, (key, value)를 소괄호로 묶어 언패킹합니다.
data = [3, -1, 4, -5, 9]
for i, value in enumerate(data):
if value < 0:
data[i] = 0
print(data)- 결과
- [3, 0, 4, 0, 9]
반복문의 변수 value에 새 값을 할당해도 목록의 요소는 바뀌지 않습니다. value는 요소를 가리키는 별도의 변수일 뿐이기 때문입니다.
목록의 요소를 직접 바꾸려면 data[i] = 0처럼 색인으로 할당해야 하며, 이때 enumerate가 제공하는 색인 값을 사용합니다.
예제는 음수인 요소의 위치(1, 3)를 찾아 0으로 바꿉니다.
- Tip : 반복 중에 목록의 값을 바꾸는 것은 안전하지만, 요소를 추가하거나 삭제하면 색인이 밀려 요소를 건너뛸 수 있으므로 주의합니다.
다중 색인 반환
두 개 이상의 목록을 같은 순서로 함께 반복하면서, 동시에 색인 값도 필요한 경우가 있습니다.
이때 제 24강에서 다룬 zip과 enumerate를 함께 사용합니다.
data1 = ["Python", "076923", "YUNDAEHEE", "X"]
data2 = ["파이썬", "076923", "윤대희"]
for i, (datum1, datum2) in enumerate(zip(data1, data2)):
print(i, datum1, datum2)- 결과
- 0 Python 파이썬
1 076923 076923
2 YUNDAEHEE 윤대희
for 색인 값, (요소 값1, 요소 값2) in enumerate(zip(반복 가능한 객체1, 반복 가능한 객체2)):의 형태로 구성됩니다.
집 함수(zip)로 두 개 이상의 반복 가능한 객체를 묶어 활용할 수 있습니다.
집 함수의 특성상 요소의 길이가 다르다면, 더 작은 길이를 갖는 반복횟수로 설정됩니다.
enumerate는 (색인 값, (요소 값1, 요소 값2)) 형태의 값을 반환하므로, 요소 값도 소괄호(())로 묶어 언패킹해야 합니다.
두 개 이상의 객체가 색인 값과 함께 반복되어 요소 값이 반환됩니다.
실행 순서로 보면, zip이 먼저 ("Python", "파이썬"), ("076923", "076923"), ("YUNDAEHEE", "윤대희")를 차례로 만들고, enumerate가 그 앞에 0, 1, 2를 붙입니다.
data1의 네 번째 요소인 X는 짝이 되는 data2의 요소가 없으므로 아무 오류 없이 무시됩니다.
소괄호를 빼고 for i, datum1, datum2 in ...으로 작성하면, 반환값은 두 개(i, 튜플)인데 변수는 세 개이므로 ValueError가 발생합니다.
- Tip : Python 3.10 이상에서는
zip(data1, data2, strict=True)로 사용하면 길이가 다를 때ValueError가 발생합니다.
열거형 클래스(Enum)
프로그램에서는 상태, 색상, 방향처럼 정해진 몇 가지 값 중 하나를 다루는 경우가 많습니다.
이를 1, 2, 3이나 "red", "green" 같은 숫자나 문자열로 표현하면, 코드에서 if color == 1:을 보고 1이 무엇을 의미하는지 알기 어렵고, "gren"처럼 오타를 내도 오류 없이 실행됩니다.
열거형 클래스(Enum)는 이런 값들에 이름을 붙여 하나의 묶음으로 정의하여, 의미를 명확히 하고 잘못된 값을 사용하면 오류가 발생하도록 합니다.
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED)
print(Color.RED.name, Color.RED.value)
print(Color(2))
print(Color["BLUE"])
print(Color.RED == 1)
for color in Color:
print(color)- 결과
- Color.RED
RED 1
Color.GREEN
Color.BLUE
False
Color.RED
Color.GREEN
Color.BLUE
열거형 클래스(Enum)는 서로 관련된 상수들을 하나의 이름 공간으로 묶어 정의하는 클래스입니다.
enum 모듈의 Enum 클래스를 상속받아 이름 = 값 형태로 멤버(member)를 정의합니다.
멤버.name으로 멤버의 이름을, 멤버.value로 멤버의 값을 확인할 수 있습니다.
클래스(값)으로 값을 통해 멤버를 찾을 수 있으며, 클래스["이름"]으로 이름을 통해 멤버를 찾을 수 있습니다.
결과를 순서대로 보면, print(Color.RED)는 값 1이 아니라 Color.RED라는 멤버 자체를 출력합니다.
Color(2)는 값이 2인 멤버인 Color.GREEN을, Color["BLUE"]는 이름이 BLUE인 멤버를 반환합니다. 값 찾기는 소괄호, 이름 찾기는 대괄호를 사용한다는 점에 주의합니다.
Color(2)는 외부에서 숫자로 받은 값(파일, 데이터베이스 등)을 멤버로 변환할 때, Color["BLUE"]는 문자열로 받은 이름을 멤버로 변환할 때 사용합니다.
Enum의 멤버는 값이 같더라도 정수와 같지 않습니다. 그러므로, Color.RED == 1은 False가 됩니다.
열거형 클래스는 반복 가능한 객체이므로, for 문으로 정의한 순서대로 멤버를 반복할 수 있습니다.
숫자나 문자열을 직접 사용하는 것보다 의미가 명확하고 오타를 방지할 수 있습니다.
Color.GRENN처럼 존재하지 않는 멤버를 사용하면 바로 AttributeError가 발생하므로, 오타를 실행 즉시 발견할 수 있습니다.
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
try:
Color(4)
except ValueError as e:
print("ValueError:", e)
try:
Color["PINK"]
except KeyError as e:
print("KeyError:", e)
try:
Color.RED = 10
except AttributeError as e:
print("AttributeError:", e)
print(Color.RED is Color(1))
print(type(Color.RED), isinstance(Color.RED, Color))- 결과
- ValueError: 4 is not a valid Color
KeyError: ‘PINK’
AttributeError: cannot reassign member ‘RED’
True
<enum ‘Color’> True
존재하지 않는 값으로 찾으면 ValueError, 존재하지 않는 이름으로 찾으면 KeyError가 발생합니다. 외부에서 받은 값을 변환할 때는 이 오류를 예외 처리합니다.
Color.RED = 10처럼 멤버에 다른 값을 할당하면 AttributeError가 발생합니다. 열거형의 멤버는 정의한 뒤 바꿀 수 없는 상수입니다.
각 멤버는 프로그램 안에 단 하나의 객체로 존재하므로, Color.RED is Color(1)은 True입니다. 그러므로, 멤버를 비교할 때는 ==과 is를 모두 사용할 수 있습니다.
type(Color.RED)가 Color인 것처럼, 각 멤버는 자신이 속한 열거형 클래스의 인스턴스입니다.
from enum import Enum
class Status(Enum):
READY = "ready"
RUNNING = "running"
DONE = "done"
def describe(status):
match status:
case Status.READY:
return "대기 중"
case Status.RUNNING:
return "실행 중"
case Status.DONE:
return "완료"
print(describe(Status.RUNNING))
print(describe(Status("done")))- 결과
- 실행 중
완료
열거형은 상태에 따라 다른 동작을 해야 하는 코드에서 자주 사용합니다.
예제는 작업 상태를 Status 열거형으로 정의하고, match 문으로 상태마다 다른 문자열을 반환합니다. (match 문은 Python 3.10 이상)
Status("done")처럼 문자열 값으로 받은 상태도 멤버로 변환하면 같은 방식으로 처리할 수 있습니다.
"runing" 같은 오타는 Status("runing")에서 바로 ValueError가 발생하므로, 잘못된 상태가 프로그램 깊숙이 전달되는 것을 막을 수 있습니다.
from enum import Enum, auto
class Direction(Enum):
UP = auto()
DOWN = auto()
LEFT = auto()
RIGHT = auto()
print(list(Direction))
print(Direction.LEFT.value)- 결과
- [<Direction.UP: 1>, <Direction.DOWN: 2>, <Direction.LEFT: 3>, <Direction.RIGHT: 4>]
3
auto()를 사용하면 멤버의 값을 자동으로 할당합니다.
Enum에서는 1부터 시작하여 1씩 증가하는 정수가 할당됩니다.
멤버의 값 자체가 중요하지 않고 이름으로만 구분할 때 유용합니다.
목록 안의 멤버는 <Direction.UP: 1>처럼 repr 형식으로 출력되어 이름과 값을 함께 확인할 수 있습니다.
- Tip :
auto()로 할당된 값은 멤버를 정의한 순서에 따라 정해지므로, 값을 파일이나 데이터베이스에 저장한다면 중간에 멤버를 추가할 때 기존 값이 바뀌지 않도록 주의합니다.
정수 & 문자열 열거형
일반 Enum의 멤버는 정수나 문자열과 비교되지 않으므로, 기존에 숫자나 문자열을 사용하던 코드와 함께 쓰기 어려울 수 있습니다.
IntEnum과 StrEnum은 멤버가 정수나 문자열 그 자체로도 동작하는 열거형으로, 이름 붙은 상수의 장점과 기존 값과의 호환성을 함께 얻을 수 있습니다.
from enum import StrEnum, IntEnum, auto
class Method(StrEnum):
GET = auto()
POST = auto()
class Level(IntEnum):
LOW = 1
HIGH = 2
print(Method.GET, repr(Method.GET))
print(Method.GET == "get")
print(Method.POST.upper())
print(Level.HIGH > Level.LOW, Level.HIGH + 1)- 결과
- get <Method.GET: ‘get’>
True
POST
True 3
IntEnum은 멤버가 정수(int)처럼 동작하는 열거형이며, StrEnum은 멤버가 문자열(str)처럼 동작하는 열거형입니다.
IntEnum의 멤버는 정수와 비교하거나 연산할 수 있습니다.
StrEnum의 멤버는 문자열과 비교하거나 문자열 메서드를 사용할 수 있습니다.
StrEnum에서 auto()를 사용하면 멤버 이름의 소문자가 값으로 할당됩니다.
결과의 Method.POST.upper()는 문자열 메서드를 호출한 결과로, 멤버가 아닌 일반 문자열 POST를 반환합니다. Level.HIGH + 1도 일반 정수 3을 반환합니다.
-
Tip :
StrEnum은 Python 3.11 이상에서 사용할 수 있습니다. -
Tip : Python 3.11 이상에서
IntEnum과StrEnum의 멤버를print()나str()로 출력하면Level.HIGH가 아닌 값(2)이 출력됩니다.
from enum import Enum, IntEnum
class Color(Enum):
RED = 1
class Level(IntEnum):
LOW = 1
print(Color.RED == 1, Level.LOW == 1)
print(Level.LOW + Level.LOW, isinstance(Level.LOW, int))
try:
print(Color.RED < Color.RED)
except TypeError as e:
print("TypeError:", e)- 결과
- False True
2 True
TypeError: ‘<’ not supported between instances of ‘Color’ and ‘Color’
같은 값 1을 가진 멤버라도, 일반 Enum은 정수와 같지 않고 IntEnum은 정수와 같습니다.
IntEnum의 멤버는 int를 상속받으므로 isinstance(Level.LOW, int)가 True이며, 정수가 필요한 곳 어디에서나 사용할 수 있습니다.
반면, 일반 Enum의 멤버는 크기 비교(<, >)를 지원하지 않아 TypeError가 발생합니다.
그러므로, 새로 작성하는 코드에서는 다른 종류의 값과 섞이지 않도록 일반 Enum을 기본으로 사용하고, 기존에 정수나 문자열을 사용하던 코드나 외부 라이브러리와 값을 주고받아야 할 때 IntEnum, StrEnum을 사용합니다.
IntEnum은 Color.RED == 1처럼 다른 열거형의 값과도 같다고 판단될 수 있어, 서로 관계없는 상수가 섞여도 오류를 발견하기 어렵다는 단점이 있습니다.
플래그 열거형(Flag)
Enum의 멤버는 한 번에 하나의 값만 나타냅니다.
하지만 파일 권한(읽기·쓰기·실행)이나 글꼴 스타일(굵게·기울임·밑줄)처럼 여러 값을 동시에 가질 수 있는 경우에는 멤버를 조합할 수 있어야 합니다.
Flag는 이런 경우에 사용하는 열거형입니다.
from enum import Flag, auto
class Permission(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()
perm = Permission.READ | Permission.WRITE
print(perm)
print(Permission.WRITE in perm)
print(Permission.EXECUTE in perm)
print(list(perm))- 결과
- Permission.READ|WRITE
True
False
[<Permission.READ: 1>, <Permission.WRITE: 2>]
Flag는 |, & 등의 비트 연산자로 멤버를 조합할 수 있는 열거형입니다.
Flag에서 auto()를 사용하면 1, 2, 4, 8처럼 2의 거듭제곱 값이 할당됩니다.
멤버 in 조합으로 특정 멤버가 포함되어 있는지 확인할 수 있습니다.
- Tip : Python 3.11 이상에서는
list(조합)으로 조합에 포함된 멤버를 반복할 수 있습니다.
from enum import Flag, auto
class Permission(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()
print([p.value for p in Permission])
perm = Permission.READ | Permission.WRITE
print(perm.value)
print(perm & Permission.WRITE)
print(perm & ~Permission.WRITE)
print(bool(perm & Permission.EXECUTE))- 결과
- [1, 2, 4]
3
Permission.WRITE
Permission.READ
False
Flag가 조합을 표현할 수 있는 이유는 각 멤버의 값이 2의 거듭제곱이기 때문입니다.
READ는 이진수 001, WRITE는 010, EXECUTE는 100으로 서로 다른 자리의 비트 하나만 사용하므로, |(OR)로 합쳐도 어떤 멤버가 포함되었는지 구분할 수 있습니다.
READ | WRITE는 001 | 010 = 011이므로 값이 3이 됩니다.
&(AND)는 두 조합에 공통으로 포함된 멤버를 반환하며, ~(NOT)는 반대 멤버를 반환합니다. 그러므로, perm & ~Permission.WRITE는 perm에서 WRITE를 제거한 READ가 됩니다.
공통 멤버가 없으면 값이 0인 빈 조합이 되며, 빈 조합은 bool로 변환하면 False가 됩니다.
- Tip : 직접 값을 지정한다면
READ = 1,WRITE = 2,EXECUTE = 4처럼 2의 거듭제곱으로 지정해야 합니다.3처럼 여러 비트를 가진 값은 다른 멤버의 조합으로 해석됩니다.
별칭과 검증(unique & verify)
열거형은 멤버마다 값이 달라야 한다고 생각하기 쉽지만, Python의 Enum은 같은 값을 가진 멤버를 허용합니다.
이 기능은 하나의 값에 여러 이름을 붙일 때 유용하지만, 실수로 같은 값을 입력한 경우에도 오류가 발생하지 않습니다.
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
CRIMSON = 1
print(Color.CRIMSON)
print(Color.CRIMSON is Color.RED)
print(list(Color))
print(Color.__members__.keys())- 결과
- Color.RED
True
[<Color.RED: 1>, <Color.GREEN: 2>]
dict_keys([‘RED’, ‘GREEN’, ‘CRIMSON’])
같은 값을 갖는 멤버를 정의하면, 뒤에 정의된 멤버는 앞의 멤버의 별칭(alias)이 됩니다.
Color.CRIMSON은 Color.RED와 동일한 객체이며, 반복할 때는 별칭이 제외됩니다.
별칭을 포함한 모든 이름은 클래스.__members__로 확인할 수 있습니다.
결과의 첫 줄처럼 Color.CRIMSON을 출력해도 Color.RED가 출력되므로, 의도하지 않은 별칭이 있다면 디버깅할 때 혼란스러울 수 있습니다.
from enum import Enum, verify, UNIQUE, CONTINUOUS
@verify(UNIQUE)
class Color(Enum):
RED = 1
GREEN = 2
CRIMSON = 1- 결과
- ValueError: aliases found in <enum ‘Color’>: CRIMSON -> RED
@verify(검사 조건) 데코레이터를 사용하면 열거형을 정의할 때 조건을 검사하고, 조건을 만족하지 않으면 ValueError를 발생시킵니다. (Python 3.11 이상)
UNIQUE는 별칭이 없는지, CONTINUOUS는 정수 값이 빠짐없이 연속되는지 검사합니다.
검사는 클래스를 정의하는 순간 실행되므로, 잘못된 열거형은 프로그램이 시작될 때 바로 발견됩니다.
from enum import Enum, verify, CONTINUOUS
@verify(CONTINUOUS)
class Grade(Enum):
A = 1
B = 2
D = 4- 결과
- ValueError: invalid enum ‘Grade’: missing values 3
@verify(CONTINUOUS)로 정의한 열거형의 값이 1, 2, 4라면 3이 빠져 있으므로 ValueError가 발생합니다.
번호가 연속되어야 하는 단계나 등급을 정의할 때, 중간 값을 빠뜨리는 실수를 막을 수 있습니다.
from enum import Enum, unique
@unique
class Color(Enum):
RED = 1
CRIMSON = 1- 결과
- ValueError: duplicate values found in <enum ‘Color’>: CRIMSON -> RED
별칭만 검사한다면 이전 버전부터 지원하는 @unique 데코레이터를 사용할 수도 있습니다.
@unique는 @verify(UNIQUE)와 같은 검사를 하며, 오류 메시지만 조금 다릅니다.
멤버 지정(member & nonmember)
열거형 클래스 안에는 멤버뿐만 아니라, 멤버와 함께 사용할 상수나 함수를 정의하고 싶을 때가 있습니다.
하지만 열거형은 클래스 본문의 값을 자동으로 멤버로 만들기 때문에, 멤버가 아닌 값을 정의하려면 별도의 표시가 필요합니다.
from enum import Enum, member, nonmember
class Unit(Enum):
METER = 1
KILOMETER = 1000
RATE = nonmember(0.001)
@member
def double(x):
return x * 2
print(len(Unit), [unit.name for unit in Unit])
print(Unit.RATE)
print(Unit.double.value(3))- 결과
- 3 [‘METER’, ‘KILOMETER’, ‘double’]
0.001
6
열거형 클래스에 정의한 값은 기본적으로 멤버가 되며, 함수(메서드)는 멤버가 되지 않습니다.
nonmember(값)을 사용하면 멤버가 아닌 일반 클래스 속성으로 정의할 수 있습니다. 그러므로, Unit.RATE는 0.001 값 그대로 반환됩니다.
@member 데코레이터나 member(값)을 사용하면 함수와 같이 원래 멤버가 되지 않는 값을 강제로 멤버로 정의할 수 있습니다.
member와 nonmember는 Python 3.11 이상에서 사용할 수 있습니다.
결과의 len(Unit)이 3인 것은 METER, KILOMETER, double이 멤버이고 RATE는 멤버가 아니기 때문입니다.
double은 멤버가 되었으므로 Unit.double은 함수가 아니라 멤버이며, 원래 함수는 Unit.double.value에 저장됩니다. 그러므로, Unit.double.value(3)으로 호출합니다.
RATE처럼 단위 변환 비율과 같이 멤버와 관련은 있지만 선택지가 아닌 값은 nonmember로 정의하면, 반복이나 len() 결과에 섞이지 않습니다.
정리
| 이름 | 설명 | 반환값/특징 |
|---|---|---|
enumerate(객체, start=0) |
색인과 요소를 함께 반복 | (색인, 요소) 튜플을 반환하는 반복자 |
enumerate(zip(a, b)) |
여러 객체를 색인과 함께 반복 | (색인, (요소1, 요소2)) |
Enum |
이름 붙은 상수 묶음 | 멤버는 값과 비교되지 않음 |
멤버.name / 멤버.value |
멤버의 이름 / 값 | str / 정의한 값 |
클래스(값) / 클래스["이름"] |
값 / 이름으로 멤버 찾기 | 없으면 ValueError / KeyError |
auto() |
값 자동 할당 | Enum은 1부터, Flag는 2의 거듭제곱 |
IntEnum / StrEnum |
정수 / 문자열처럼 동작하는 열거형 | StrEnum은 3.11 이상 |
Flag |
비트 연산으로 조합 가능한 열거형 | 비트 연산자와 in 사용 |
@unique / @verify(...) |
별칭·연속성 검사 | 조건 위반 시 ValueError, verify는 3.11 이상 |
member / nonmember |
멤버 여부 지정 | 3.11 이상 |
enumerate는 반복할 때 색인이 필요하면 사용하는 함수이며, range(len(...))보다 짧고 의도가 명확한 코드를 작성할 수 있습니다.
Enum은 의미를 알기 어려운 숫자나 문자열 대신 이름 붙은 상수를 사용하게 하여, 코드의 의미를 명확히 하고 잘못된 값을 즉시 오류로 발견하게 합니다.
기본적으로 Enum을 사용하고, 기존 값과 호환이 필요하면 IntEnum·StrEnum을, 여러 값을 조합해야 하면 Flag를 선택합니다.
댓글 남기기