- Python
Python Enumの使い方|StrEnum・auto・match文まで一覧解説
PythonのEnum(列挙型)とは、「決まった選択肢の集まり」に名前を付けて1つの型として扱う仕組みで、標準ライブラリの enum モジュールで定義します。 class Status(Enum): のようにクラスを書き、Status.TODO のように使うと、タイプミスに気づきやすく、取りうる値が一目でわかるコードになります。
この記事では、Enum / IntEnum / StrEnum / Flag / IntFlag と、auto / unique / member / nonmember / verify を 1つの比較表 にまとめ、すべてのコードを Python 3.11.15 と 3.14.7 で実際に動かした実行結果 つきで解説します。基本の取り出し方に加えて、match文、JSON・SQLite・Pydantic・dataclass との組み合わせ、定数クラスや Literal 型との使い分けの判断基準(mypy の出力つき)、そして「IntEnum は int と等しくなる」「値が重複するとエイリアスになる」といった つまずきやすい点 まで1本で確認できます。
Python Enumの早見表
種類と機能の比較表
| 名前 | 追加された版 | 値の型 | == で生の値と比べると |
str() の結果 |
主な用途 |
|---|---|---|---|---|---|
Enum |
3.4 | 何でも | False(Color.RED == 1 は False) |
'Color.RED' |
一般的な選択肢 |
IntEnum |
3.4 | int |
True(Priority.HIGH == 3) |
'3'(3.11以降) |
大小比較・数値と混ぜて使う |
StrEnum |
3.11 | str |
True(Status.TODO == "todo") |
'todo' |
JSON・DB・APIで文字列として扱う |
Flag |
3.6 | int(ビット) |
False |
'Perm.READ|WRITE' |
組み合わせ可能な権限・設定 |
IntFlag |
3.6 | int(ビット) |
True(Mode(6) == 6) |
'6'(3.11以降) |
OSの定数など int として渡す値 |
auto() |
3.6 | ― | ― | ― | 値を自動で割り当てる(Enumは1,2,3…、StrEnumは名前の小文字、Flagは1,2,4…) |
@unique |
3.4 | ― | ― | ― | 値の重複(エイリアス)を禁止する |
member() / nonmember() |
3.11 | ― | ― | ― | 関数をメンバーにする/属性をメンバーにしない |
@verify(...) |
3.11 | ― | ― | ― | UNIQUE・CONTINUOUS・NAMED_FLAGS の制約チェック |
操作の逆引き早見表
| やりたいこと | 書き方 | 結果の例 |
|---|---|---|
| 名前を取る | Color.RED.name |
'RED' |
| 値を取る | Color.RED.value |
1 |
| 値からメンバーを取る | Color(1) |
Color.RED(ないと ValueError) |
| 名前の文字列からメンバーを取る | Color["RED"] |
Color.RED(ないと KeyError) |
| 全メンバーを列挙 | list(Color) |
エイリアスを除く全メンバー |
| メンバー数 | len(Color) |
3 |
| 名前→メンバーの辞書(エイリアス込み) | Color.__members__ |
{'RED': <Color.RED: 1>, ...} |
| 同じメンバーか比較 | c is Color.RED |
True / False |
| メンバーかどうか | Color.RED in Color |
True |
| 値が含まれるか(3.12以降) | 1 in Color |
True(3.11は TypeError) |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Python Enumの使い方|StrEnum・auto・match文まで一覧解説」
Enumの基本:定義・取得・列挙・比較
Enum を継承したクラスに 名前 = 値 を並べると、それぞれが「メンバー」になります。 次のコードで、基本操作をまとめて確認します。
import sys
from enum import Enum
print(sys.version.split()[0])
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
print(Color.RED, repr(Color.RED), Color.RED.name, Color.RED.value)
print(Color(1), Color["RED"], getattr(Color, "BLUE"))
print(list(Color), len(Color))
print([c.name for c in Color], [c.value for c in Color])
print(Color.RED is Color(1), Color.RED == Color.RED, Color.RED == 1)
print(type(Color.RED), isinstance(Color.RED, Color))
print(Color.__members__)
print({Color.RED: "赤"}[Color.RED])
実行結果(Python 3.11.15。3.14.7でも同じ出力):
3.11.15
Color.RED <Color.RED: 1> RED 1
Color.RED Color.RED Color.BLUE
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>] 3
['RED', 'GREEN', 'BLUE'] [1, 2, 3]
True True False
<enum 'Color'> True
{'RED': <Color.RED: 1>, 'GREEN': <Color.GREEN: 2>, 'BLUE': <Color.BLUE: 3>}
赤
Color(1)は値から、Color["RED"]は名前から同じメンバーを取り出せます。 外部から届いた値(JSONの値やDBの文字列)を Enum に戻すときに使います。- 各メンバーはただ1つのオブジェクトなので、
isでも==でも比較できます。 - 普通の
EnumはColor.RED == 1がFalseです。 値と比べたいときはColor.RED.value == 1と書きます。 - メンバーはハッシュ可能なので、辞書のキーにも使えます。
存在しない値・名前、再代入、大小比較のエラー
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
try:
Color(9)
except ValueError as e:
print("ValueError:", e)
try:
Color["PINK"]
except KeyError as e:
print("KeyError:", e)
try:
Color.RED = 5
except AttributeError as e:
print("AttributeError:", e)
try:
Color.RED < Color.GREEN
except TypeError as e:
print("TypeError:", e)
try:
print(1 in Color)
except TypeError as e:
print("TypeError:", e)
実行結果:
| 操作 | Python 3.11.15 | Python 3.14.7 |
|---|---|---|
Color(9) |
ValueError: 9 is not a valid Color |
同じ |
Color["PINK"] |
KeyError: 'PINK' |
同じ |
Color.RED = 5 |
AttributeError: cannot reassign member 'RED' |
同じ |
Color.RED < Color.GREEN |
TypeError: '<' not supported between instances of 'Color' and 'Color' |
同じ |
1 in Color |
DeprecationWarning のあと TypeError: unsupported operand type(s) for 'in': 'int' and 'EnumType' |
True |
メンバーは再代入できないので、定数として安心して使えます。 また 1 in Color のように値で含まれるかを調べる書き方は 3.12 から使えるようになりました。 3.11 も対象にするコードでは 1 in {c.value for c in Color} と書くと、どちらでも動きます。
IntEnum・StrEnum・Flag・IntFlag の違いを実行で比べる
from enum import IntEnum, StrEnum, Flag, IntFlag, auto
class Priority(IntEnum):
LOW = 1
MID = 2
HIGH = 3
print(Priority.HIGH == 3, Priority.HIGH > Priority.LOW, Priority.LOW + 1, sorted([Priority.HIGH, Priority.LOW]))
print(str(Priority.HIGH), f"{Priority.HIGH}", repr(Priority.HIGH))
class Status(StrEnum):
TODO = auto()
DOING = auto()
DONE = "done"
print(Status.TODO, repr(Status.TODO), Status.TODO == "todo", f"[{Status.DOING}]", Status.DONE.upper(), Status("done"))
print("todo" in [s.value for s in Status], isinstance(Status.TODO, str))
class Perm(Flag):
READ = auto()
WRITE = auto()
EXEC = auto()
rw = Perm.READ | Perm.WRITE
print(rw, repr(rw), Perm.READ in rw, Perm.EXEC in rw, bool(Perm(0)), list(rw), rw.value)
print(~Perm.READ, Perm(7))
class Mode(IntFlag):
R = 4
W = 2
X = 1
print(Mode.R | Mode.W, Mode(6), Mode(6) == 6, Mode.R | 8)
実行結果(Python 3.11.15。3.14.7でも同じ出力):
True True 2 [<Priority.LOW: 1>, <Priority.HIGH: 3>]
3 3 <Priority.HIGH: 3>
todo <Status.TODO: 'todo'> True [doing] DONE done
True True
Perm.READ|WRITE <Perm.READ|WRITE: 3> True False False [<Perm.READ: 1>, <Perm.WRITE: 2>] 3
Perm.WRITE|EXEC Perm.READ|WRITE|EXEC
6 6 True 12
| 種類 | 結果から読み取れること |
|---|---|
IntEnum |
> で大小比較でき、+ 1 すると普通の int(2)になる。 sorted もそのまま使える |
StrEnum |
auto() で名前の小文字('todo')が値になる。 str のメソッド(.upper())も使え、print や f-string では値がそのまま出る |
Flag |
| で組み合わせ、in で含まれるかを調べる。 ~ で反転、Perm(0) は偽。list(rw) で中身を分解できる |
IntFlag |
組み合わせても int として扱え、定義にない 8 を足しても 12 のまま保持される |
どれを選ぶかの判断表
| こんなとき | 選ぶもの |
|---|---|
| 選択肢を表したいだけ(値に意味がない) | Enum + auto() |
| JSON・DB・APIで文字列としてやりとりする | StrEnum |
| 優先度や段階など、大小比較したい | IntEnum |
| 複数を同時に持てる(読み・書き・実行など) | Flag |
| 外部の関数に int のビット値として渡す | IntFlag |
| 数値と混ざって比較されると困る | Enum(IntEnum にしない) |
auto・unique・verify・member/nonmember の使い方
auto で値を自動採番する
from enum import Enum, StrEnum, auto
class Seq(Enum):
A = auto()
B = auto()
print([(m.name, m.value) for m in Seq])
class Lower(StrEnum):
UserName = auto()
print(Lower.UserName.value)
[('A', 1), ('B', 2)]
username
auto() は Enum では 1 から順に、StrEnum ではメンバー名を小文字にした文字列を割り当てます。 UserName のような名前も username になる点は覚えておくと安心です。
値が重複するとエイリアスになる/@unique で禁止する
from enum import Enum, unique
class Shape(Enum):
SQUARE = 2
DIAMOND = 1
CIRCLE = 3
ALIAS_FOR_SQUARE = 2
print(Shape.ALIAS_FOR_SQUARE, Shape.ALIAS_FOR_SQUARE is Shape.SQUARE, list(Shape), list(Shape.__members__))
try:
@unique
class Mistake(Enum):
ONE = 1
TWO = 1
except ValueError as e:
print("ValueError:", e)
Shape.SQUARE True [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>] ['SQUARE', 'DIAMOND', 'CIRCLE', 'ALIAS_FOR_SQUARE']
ValueError: duplicate values found in <enum 'Mistake'>: TWO -> ONE
同じ値を持つメンバーは、最初のメンバーの「別名(エイリアス)」になります。 list(Shape) には出てこず、__members__ にだけ残ります。値の書き間違いでうっかり重複させないためには @unique を付けると、定義した時点で ValueError にできます。
@verify で連番などの制約をチェックする(3.11+)
from enum import IntEnum, verify, CONTINUOUS
try:
@verify(CONTINUOUS)
class Level(IntEnum):
A = 1
B = 2
C = 4
except ValueError as e:
print("ValueError:", e)
ValueError: invalid enum 'Level': missing values 3
verify の引数 |
チェック内容 |
|---|---|
UNIQUE |
値の重複がない(@unique と同じ) |
CONTINUOUS |
整数値に抜けがない |
NAMED_FLAGS |
Flag の組み合わせ値が、すべて名前付きのフラグでできている |
メソッド・プロパティ・タプル値・member/nonmember
Enumは普通のクラスと同じようにメソッドやプロパティを追加できます。 値をタプルにして __init__ で受け取ると、1つのメンバーに複数の属性を持たせられます。
from enum import Enum, member, nonmember
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
EARTH = (5.976e+24, 6.37814e6)
def __init__(self, mass, radius):
self.mass = mass
self.radius = radius
@property
def gravity(self):
G = 6.673e-11
return G * self.mass / (self.radius * self.radius)
print(Planet.EARTH.value, round(Planet.EARTH.gravity, 2))
class Op(Enum):
ADD = member(lambda a, b: a + b)
SUB = member(lambda a, b: a - b)
note = nonmember("メモ")
def __call__(self, *args):
return self.value(*args)
print([m.name for m in Op], Op.ADD(2, 3), Op.note)
(5.976e+24, 6378140.0) 9.8
['ADD', 'SUB'] 5 メモ
通常、クラス内の関数(lambda を含む)はメソッドとして扱われ、メンバーになりません。 member() で包むとメンバーになり、逆に nonmember() で包んだ値はメンバーにならず、ただのクラス属性になります。
StrEnumにメソッドを足して使う(タスクの状態の例)
状態を表す StrEnum に「表示名」「次の状態」「文字列からの変換」を持たせると、状態に関する処理を1か所にまとめられます。 以降の例でもこの Status を使います。
from enum import StrEnum, auto
class Status(StrEnum):
TODO = auto()
DOING = auto()
DONE = auto()
@property
def label(self) -> str:
return {"todo": "未着手", "doing": "対応中", "done": "完了"}[self.value]
def next(self) -> "Status":
members = list(Status)
i = members.index(self)
return members[min(i + 1, len(members) - 1)]
@classmethod
def parse(cls, text: str) -> "Status":
return cls(text.strip().lower())
print(Status.TODO.label, Status.TODO.next(), Status.DONE.next(), Status.parse(" DOING "))
未着手 doing done doing
_missing_ で値の受け取り方を広げる
from enum import Enum
class Size(Enum):
S = 1
@classmethod
def _missing_(cls, value):
if isinstance(value, str):
for m in cls:
if m.name == value.upper():
return m
return None
print(Size("s"))
try:
Size(5)
except ValueError as e:
print("ValueError:", e)
Size.S
ValueError: 5 is not a valid Size
_missing_ は値が見つからなかったときに呼ばれるクラスメソッドです。名前の小文字や旧表記などを受け付けたいときに使い、該当しなければ None を返すと通常どおり ValueError になります。
match文と組み合わせる
Enumのメンバーは case Status.TODO: のように「ドット付きの名前」で書くと、値のパターンとして比較されます。 | で複数をまとめることもできます。
from enum import Enum, StrEnum, auto
class Status(StrEnum):
TODO = auto()
DOING = auto()
DONE = auto()
def describe(s: Status) -> str:
match s:
case Status.TODO:
return "これから着手"
case Status.DOING | Status.DONE:
return f"{s}のタスク"
for s in Status:
print("match:", s, "->", describe(s))
class Color(Enum):
RED = 1
GREEN = 2
def f(c):
match c:
case Color.RED:
return "red"
case _:
return "other"
print(f(Color.RED), f(1))
実行結果(Python 3.11.15):
match: todo -> これから着手
match: doing -> doingのタスク
match: done -> doneのタスク
red other
普通の Enum は 1 と等しくないため、f(1) は case _ に進みます。
mypy で「case の書き漏れ」を見つける
case _: assert_never(s) を最後に置くと、メンバーを追加して case を書き忘れたときに型チェッカーが知らせてくれます。
from enum import StrEnum, auto
from typing import assert_never
class Status(StrEnum):
TODO = auto()
DONE = auto()
def label(s: Status) -> str:
match s:
case Status.TODO:
return "未着手"
case _:
assert_never(s)
mypy 1.20.2 の出力(ファイル名を label.py として実行):
label.py:13: error: Argument 1 to "assert_never" has incompatible type "Literal[Status.DONE]"; expected "Never" [arg-type]
Status.DONE の case がないことを、実行前に指摘してくれました。 assert_never は Python 3.11 から typing に入っています。
JSON・SQLite・dataclass・Pydanticと組み合わせる
StrEnum(と IntEnum)は str・int のサブクラスなので、JSONやDBにそのまま渡せます。 普通の Enum は変換が必要です。
import json
import sqlite3
from dataclasses import dataclass, asdict
from enum import Enum, StrEnum, auto
class Status(StrEnum):
TODO = auto()
DOING = auto()
DONE = auto()
class Color2(Enum):
RED = "red"
# JSON に書く/読む
print(json.dumps({"id": 1, "status": Status.DOING}))
try:
json.dumps({"c": Color2.RED})
except TypeError as e:
print("TypeError:", e)
print(json.dumps({"c": Color2.RED}, default=lambda o: o.value if isinstance(o, Enum) else o))
loaded = json.loads('{"id": 1, "status": "doing"}')
print(Status(loaded["status"]), repr(Status(loaded["status"])))
# dataclass
@dataclass
class Task:
title: str
status: Status = Status.TODO
t = Task("備品を発注")
print(t, asdict(t), json.dumps(asdict(t), ensure_ascii=False))
# SQLite
con = sqlite3.connect(":memory:")
con.execute("create table task(title text, status text)")
con.execute("insert into task values (?, ?)", ("在庫確認", Status.DONE))
row = con.execute("select title, status from task").fetchone()
print(row, Status(row[1]))
try:
con.execute("insert into task values (?, ?)", ("x", Color2.RED))
except Exception as e:
print(type(e).__name__, e)
実行結果(Python 3.11.15。3.14.7でも同じ出力):
{"id": 1, "status": "doing"}
TypeError: Object of type Color2 is not JSON serializable
{"c": "red"}
doing <Status.DOING: 'doing'>
Task(title='備品を発注', status=<Status.TODO: 'todo'>) {'title': '備品を発注', 'status': <Status.TODO: 'todo'>} {"title": "備品を発注", "status": "todo"}
('在庫確認', 'done') done
ProgrammingError Error binding parameter 2: type 'Color2' is not supported
| 渡し先 | StrEnum / IntEnum |
普通の Enum |
|---|---|---|
json.dumps |
そのまま文字列・数値になる | TypeError → default= で .value に変換 |
SQLite(? パラメータ) |
そのまま保存できる | ProgrammingError → .value を渡す |
| 読み戻し | Status(row[1]) で Enum に戻す |
Color2(row[1]) で戻す |
dataclass の asdict |
Enumメンバーのまま入る(JSON化はそのままOK) | Enumメンバーのまま入る |
保存するときは「値」、読み込んだら Status(値) で Enum に戻す、という往復を決めておくと扱いやすくなります。
Pydantic v2 で検証する
from enum import StrEnum, auto
from pydantic import BaseModel, ValidationError, ConfigDict
class Status(StrEnum):
TODO = auto()
DOING = auto()
DONE = auto()
class TaskIn(BaseModel):
title: str
status: Status
m = TaskIn(title="記事を書く", status="doing")
print(repr(m.status), m.model_dump(), m.model_dump(mode="json"), m.model_dump_json())
try:
TaskIn(title="x", status="pending")
except ValidationError as e:
print(e)
class TaskOut(BaseModel):
model_config = ConfigDict(use_enum_values=True)
status: Status
print(repr(TaskOut(status="done").status))
実行結果(Python 3.11.15、pydantic 2.13.3):
<Status.DOING: 'doing'> {'title': '記事を書く', 'status': <Status.DOING: 'doing'>} {'title': '記事を書く', 'status': 'doing'} {"title":"記事を書く","status":"doing"}
1 validation error for TaskIn
status
Input should be 'todo', 'doing' or 'done' [type=enum, input_value='pending', input_type=str]
For further information visit https://errors.pydantic.dev/2.13/v/enum
'done'
文字列 "doing" を渡すと自動で Status.DOING に変換され、選択肢にない "pending" は ValidationError になります。 model_dump(mode="json") は値の文字列に、use_enum_values=True を付けるとモデル内でも値の文字列で保持します。
定数クラス・Literal型・Enumの使い分け
選択肢を表す方法は主に3つあり、「型チェックでどこまで守りたいか」「実行時にメンバーを列挙したいか」で選びます。 3つを mypy でチェックした結果がこちらです。
from enum import StrEnum, auto
from typing import Final, Literal
class StatusConst:
TODO: Final = "todo"
DONE: Final = "done"
StatusLit = Literal["todo", "done"]
class Status(StrEnum):
TODO = auto()
DONE = auto()
def by_const(s: str) -> None: ...
def by_lit(s: StatusLit) -> None: ...
def by_enum(s: Status) -> None: ...
by_const("tood")
by_lit("tood")
by_enum("todo")
by_enum(Status.TODO)
mypy 1.20.2 の出力(ファイル名を choices.py として実行):
choices.py:19: error: Argument 1 to "by_lit" has incompatible type "Literal['tood']"; expected "Literal['todo', 'done']" [arg-type]
choices.py:20: error: Argument 1 to "by_enum" has incompatible type "str"; expected "Status" [arg-type]
定数クラスの引数は str なので、タイプミス "tood" は検出されません。 Literal は書き間違いを検出し、Enum はメンバー以外(ただの文字列)を受け付けないようにできます。
| 観点 | 定数クラス | Literal 型 |
Enum / StrEnum |
|---|---|---|---|
| タイプミスの検出(mypy) | されない | される | される |
| 実行時に一覧を取る | 自分で書く | typing.get_args() で取れる |
list(Status) |
| メソッド・表示名を持たせる | できる(別管理) | できない | できる |
| 外部の文字列を検証して変換 | 自分で書く | 自分で書く | Status("todo") で ValueError |
| 文字列のまま扱える | はい | はい | StrEnum なら はい |
| 書く量 | 少ない | 最も少ない | やや多い |
| 判断の目安 | おすすめ |
|---|---|
| 関数の引数を2〜3個の文字列に絞りたいだけ | Literal |
| 選択肢に表示名・遷移などの振る舞いがある | StrEnum(または Enum) |
| 外部入力を受け取り、検証して変換したい | StrEnum |
| 選択肢ではない設定値(タイムアウト秒数など) | Final の定数 |
つまずきやすいポイント
1. IntEnum は int や別の IntEnum とも等しくなる
from enum import Enum, IntEnum
class Priority(IntEnum):
LOW = 1
HIGH = 2
class Size(IntEnum):
S = 1
M = 2
print(Priority.LOW == Size.S, Priority.LOW == 1, {1: "one"}[Priority.LOW], Priority.HIGH * 10)
class P2(Enum):
LOW = 1
print(P2.LOW == 1, P2.LOW.value == 1)
True True one 20
False True
IntEnum は int として比較されるため、意味の違う Priority.LOW と Size.S も等しくなります。 混同を避けたいときは普通の Enum を使い、値は .value で取り出します。
2. str と Enum の多重継承と StrEnum では str() が違う
from enum import Enum, StrEnum
class Old(str, Enum):
TODO = "todo"
class New(StrEnum):
TODO = "todo"
print(repr(str(Old.TODO)), repr(f"{Old.TODO}"), repr(str(New.TODO)), repr(f"{New.TODO}"), Old.TODO == "todo")
実行結果(3.11.15・3.14.7とも):
'Old.TODO' 'Old.TODO' 'todo' 'todo' True
class Old(str, Enum) は比較では文字列として振る舞いますが、str() や f-string では 'Old.TODO' になります。 ファイル名やURLの組み立てに使うと意図しない文字列になるので、3.11以降は StrEnum を使うと値がそのまま出ます。 3.10以前も対象にするなら .value を明示します。
3. StrEnum には文字列以外の値を書けない
from enum import StrEnum
try:
class Bad(StrEnum):
A = 1
except TypeError as e:
print("TypeError:", e)
TypeError: 1 is not a string
4. Flag の組み合わせは名前がまとめて表示される
from enum import Flag, auto
class Perm(Flag):
READ = auto()
WRITE = auto()
EXEC = auto()
RW = READ | WRITE
print(list(Perm), list(Perm.__members__), Perm.RW, repr(Perm(3)), repr(Perm(0)))
try:
Perm(8)
except ValueError as e:
print("ValueError:", e)
print(len(Perm), Perm(7))
[<Perm.READ: 1>, <Perm.WRITE: 2>, <Perm.EXEC: 4>] ['READ', 'WRITE', 'EXEC', 'RW'] Perm.RW <Perm.RW: 3> <Perm: 0>
ValueError: <flag 'Perm'> invalid value 8
given 0b0 1000
allowed 0b0 0111
3 Perm.READ|WRITE|EXEC
3.11以降の Flag は、list(Perm) や len(Perm) が1ビットの基本フラグだけを数えます。 組み合わせに名前(RW)を付けておくと表示がその名前になり、名前がない組み合わせは Perm.READ|WRITE|EXEC のように | で並びます。定義にないビット(8)は Flag では ValueError、IntFlag ではそのまま保持されます。
つまずきチェックリスト
| 症状 | 原因 | 直し方 |
|---|---|---|
Color.RED == 1 が False |
普通の Enum は値と等しくない | .value で比べる/IntEnum にする |
| 一覧にメンバーが足りない | 値が重複してエイリアスになった | @unique を付ける |
f-string で Old.TODO と出る |
(str, Enum) の str() |
StrEnum にする/.value |
json.dumps で TypeError |
普通の Enum は JSON 化できない | StrEnum にする/default= |
1 in Color で TypeError |
3.11 以前の仕様 | 3.12以降にする/.value の集合で調べる |
| 関数をメンバーにしたのに一覧にない | 関数はメソッド扱い | member() で包む |
よくある質問
Q. Enum の値から名前を取るにはどうしますか?
A. Color(1).name で 'RED' が取れます。 逆に名前の文字列からは Color["RED"]、値は .value です。
Q. StrEnum は何バージョンから使えますか?
A. Python 3.11 からです。 3.10以前では class Status(str, Enum) で近い動きになりますが、str() の結果が 'Status.TODO' になる違いがあります。
Q. Enum と Literal 型はどちらを使えばよいですか?
A. 引数を数個の文字列に絞るだけなら Literal、表示名やメソッド、外部入力の検証まで持たせたいなら StrEnum が向いています。 どちらも mypy でタイプミスを検出できます。
Q. match 文で Enum を使うときの書き方は?
A. case Status.TODO: のようにクラス名付きで書きます。 最後に case _: assert_never(s) を置くと、case の書き漏れを型チェッカーが知らせてくれます。
まとめ
- Enum は「決まった選択肢」に名前を付ける型。
Color(1)で値から、Color["RED"]で名前から取り出せる - JSON・DB・APIとやりとりするなら
StrEnum(3.11+)、大小比較ならIntEnum、組み合わせならFlag auto()は Enum では連番、StrEnum では名前の小文字。値の重複は@uniqueで防ぐ- メソッド・プロパティ・
_missing_を足すと、状態に関する処理を1か所にまとめられる - match 文は
case Status.TODO:と書き、assert_neverで書き漏れを mypy に検出させる - 引数を絞るだけなら
Literal、振る舞いや入力検証まで持たせるなら Enum と使い分ける
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Python Enumの使い方|StrEnum・auto・match文まで一覧解説」
株式会社RJCでは、PythonのEnumのような型の使い方を仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。