順番に読み進めながら学べます

enum と dataclasses — 名前付き定数とデータクラス

Enumでの文字列定数の置き換え、IntEnum+auto()の自動採番とソート、@dataclassの定型コード自動生成、field(default_factory=list)を実例で学べます。

値の意味を明示するための 2 つのモジュールを扱います。enumコード中に直書きした文字列リテラルを、名前付き定数に置き換えるためのもので、タイポを実行時に検出できます。dataclasses「データを持つだけのクラス」を 1 行で定義できる仕組みで、__init__ / __eq__ / __repr__の定型コードを省きます。

Enum — 名前付き定数で文字列リテラルを置き換える

コード中に"paid" / "shipped"のような文字列リテラルが散らばると、タイポ("shippped" のような)が実行時まで気付けず、補完も効かないため変更にも弱くなります。Enum「定数の集まりをクラスとして定義する」ことでこの問題を解決します — 定義した名前はエディタで補完が効きtypo すると AttributeError で即座にエラーになり、反復(全候補の列挙)もそのままでき、辞書のキーや switch のラベルとしても安全に使えます。

# コード中に「ステータス文字列」が散らばっている例
if status == "paid":
    ship_order(order_id)
elif status == "shippped":   # タイポ — "shipped" のはずが、実行時まで気付けない
    notify_shipped(order_id)
elif status == "cancelled":
    refund(order_id)
文字列リテラルと Enum の比較
if status == "paid":(文字列リテラル)typo "paied" でも例外は出ない→ バグが残るif status == OrderStatus.PAID:(Enum)OrderStatus.PAEID でAttributeError→ 即座に気付ける
素の文字列は補完が効かず、typo すれば実行時まで気付けない。Enum定義した名前のみ許容され、補完・タイポ検出・全候補の反復が一気に手に入る。
from enum import Enum

class OrderStatus(Enum):
    PENDING = "pending"
    PAID = "paid"
    SHIPPED = "shipped"
    CANCELLED = "cancelled"

# メンバアクセス: 名前と値の両方を持つ
print(OrderStatus.PAID)            # OrderStatus.PAID
print(OrderStatus.PAID.name)       # 'PAID'
print(OrderStatus.PAID.value)      # 'paid'

# 比較は == で
status = OrderStatus.PAID
if status == OrderStatus.PAID:
    print("支払い済み")

注文ステータスを Enum で定義し、メンバの情報を取り出します

① enum モジュールから Enum を読み込んでください

OrderStatusという Enum クラスにPENDING / PAID / SHIPPED / CANCELLEDの 4 メンバを定義してください(値はそれぞれ小文字の文字列"pending" / "paid" / "shipped" / "cancelled"

OrderStatus.PAID.namePAID の name: ◯◯の形で表示してください

OrderStatus.PAID.valuePAID の value: ◯◯の形で表示してください

⑤ 全メンバの名前を全候補: ◯の形でリスト化して表示してください(for s in OrderStatusで反復できます)

(正しく実行できれば解説が表示されます)

Python エディタ

コードを実行してください

Enum メンバを if/elif で比較して、ステータスごとのメッセージを返す関数を作ります。文字列リテラルではなくメンバ同士の比較で分岐するのが安全な書き方です。

① 実践 1 と同じOrderStatusを定義してください

get_message(status)関数を定義し、内部の if/elif で各メンバごとに次のメッセージを返してください — PENDING→「支払い待ちです」、PAID→「発送準備中です」、SHIPPED→「発送済みです」、CANCELLED→「キャンセル済みです」

get_message(OrderStatus.PAID)PAID: ◯の形で表示してください

get_message(OrderStatus.SHIPPED)SHIPPED: ◯の形で表示してください

Python エディタ

コードを実行してください

IntEnum と auto — 自動採番と数値比較

IntEnumint を継承した Enumで、メンバが整数として比較・計算できる点が特徴です。優先度・レベル・順序など、「数の大小に意味がある定数群」に向きます。auto()値を自分で書く代わりに自動採番してくれる関数で、auto()を並べるだけで1, 2, 3, 4...のように番号が振られます。

値の具体的な数字に意味が無い場合(並びさえ正しければよい場合)はauto() を使うほうが、追加・削除で番号を手で振り直す必要がなく安全です。

IntEnum と auto の組み合わせ
class Priority(IntEnum): LOW = auto() MEDIUM = auto()auto() が1, 2, 3 を自動採番Priority.LOW < Priority.HIGH→ True (int 比較)
auto()1, 2, 3, ...と自動で番号を振る。IntEnumint との比較が成り立つので、Priority.LOW < Priority.HIGHのように数の大小で並びを表現できる。

Priority を IntEnum + auto で定義し、複数のタスクを優先度の高い順に並べ替えますauto()で自動採番されることと、IntEnum が int として比較・ソートできることを実用シナリオで確認します。

① enum からIntEnumautoを読み込んでください

Priorityという IntEnum クラスにLOW / MEDIUM / HIGH / URGENTの 4 メンバを定義してください(値はすべてauto()

③ 全メンバのvalueをリスト化して採番: ◯の形で表示してください(auto()1, 2, 3, 4を割り当てたことを確認)

④ タスクのリスト[("掃除", Priority.LOW), ("メール返信", Priority.HIGH), ("資料作成", Priority.URGENT), ("レビュー", Priority.MEDIUM)]優先度の高い順にソートし、実行順:の見出しの後に各タスクを- 名前 (優先度)の形式で表示してください

Python エディタ

コードを実行してください

@dataclass — データを持つクラスを 1 行で定義する

「フィールドだけ持つ素朴なクラス」を自分で書こうとすると、__init__で属性を初期化し、__eq__==比較で呼ばれる特殊メソッド)で内容比較を実装し、__repr__printや対話シェルで呼ばれる文字列表現の特殊メソッド)で読みやすい表示を作り、と同じパターンの定型コード(boilerplate、毎回ほぼ同じ書き方をする決まり文句のコード)が並びがちです。@dataclassデコレータを 1 行付けるだけで、Python が型ヒント付きフィールドの宣言からこれらを自動生成してくれます。

つまり、型ヒント付きの属性を並べるだけでクラスが完成するということです — 既存のクラスよりはるかに少ないコードで、必要な機能が揃います。

@dataclass が自動生成するもの
@dataclassclass Order: id: int customer: str→ 自動生成__init__属性の初期化__eq__属性が同じなら ==__repr__Order(id=..., customer=...)
フィールド宣言(型ヒント付き)を並べるだけで、__init__ / __eq__ / __repr__ の 3 つを自動生成してくれる。field(default_factory=list)で空リスト等のミュータブル既定値を安全に設定でき、frozen=Trueで不変クラス(属性変更不可)にもできる。

ミュータブル既定値は default_factory で

@dataclassでリストを既定値にするとき、items: list = [] と書くと SyntaxError(または非推奨警告)になります。これは「全インスタンスで同じリストを共有してしまう」古典的バグの予防です。代わりにfield(default_factory=list)を使うと、インスタンスごとに新しい空リストが生成されて安全です。dict / set でも同様で、field(default_factory=dict)のように書きます。

注文 Order を @dataclass で定義し、自動生成された __eq__ と __repr__ を確認します

① dataclasses からdataclassfieldを読み込んでください

@dataclassを付けたOrderクラスを定義してください — フィールドはid: intcustomer: stritems: list = field(default_factory=list)is_paid: bool = Falseの 4 つ

Order(id=1234, customer="Alice", items=["apple", "banana"])でインスタンスを作り、そのままprintで表示してください(__repr__が自動生成されています)

④ 同じ内容のもう 1 つのインスタンスを作り、==で比較した結果を等しい: True / Falseの形で表示してください

⑤ 1 つ目のインスタンスのis_paidTrueに書き換えてから、もう一度==で比較した結果を変更後に等しい: True / Falseの形で表示してください

Python エディタ

コードを実行してください
QUIZ

理解度チェック

まずは1問ずつ答えてみましょう。

Q1文字列リテラル "paid"の比較をEnum に置き換えることで得られるメリットはどれですか?

Q2IntEnumauto()を使うメリットはどれですか?

Q3@dataclassリストを既定値にしたい場合、正しい書き方はどれですか?