9.4 列挙型による定数の定義を行う — enum
プログラムを書いていると、「注文のステータス(処理中、発送済み、完了)」や「ユーザーの権限(一般、管理者)」など、 限られたいくつかの状態(定数) を表現したい場面がよく登場します。
これらを単なる数字(1, 2, 3)や文字列("pending", "shipped")で管理すると、タイポによるバグが発生しやすく、後からコードを読んだときに意味がわかりにくくなります。
そこで活躍するのが、Python 3.4から標準ライブラリに追加された enum(列挙型)モジュールです。
本記事では、「9.4 列挙型による定数の定義を行う」として、enum を使った堅牢なプログラミング手法を解説します。
1. 列挙型(Enum)の基本
Section titled “1. 列挙型(Enum)の基本”Enum クラスを継承することで、関連する定数をひとまとめにした独自の列挙型を定義できます。
from enum import Enum
# 曜日を表す列挙型を定義class Weekday(Enum): MONDAY = 1 TUESDAY = 2 WEDNESDAY = 3 THURSDAY = 4 FRIDAY = 5 SATURDAY = 6 SUNDAY = 7値の取得とプロパティ
Section titled “値の取得とプロパティ”定義した列挙型のメンバー(要素)には、ドット表記でアクセスします。それぞれのメンバーは、name(名前)と value(値)というプロパティを持っています。
today = Weekday.WEDNESDAY
print(today) # 出力: Weekday.WEDNESDAYprint(type(today)) # 出力: <enum 'Weekday'>
print(today.name) # 出力: WEDNESDAY (文字列)print(today.value) # 出力: 3 (整数)2. なぜ Enum を使うべきなのか?(メリット)
Section titled “2. なぜ Enum を使うべきなのか?(メリット)”メリット1:タイポを未然に防げる
Section titled “メリット1:タイポを未然に防げる”単なる文字列 "wednesday" を引数に取る関数だと、"wednesdy" と打ち間違えても実行するまで(あるいは予期せぬ挙動をするまで)エラーになりません。
しかし、Weekday.WEDNESDY と打ち間違えれば、その場で AttributeError が発生するため、即座にバグに気づくことができます。
メリット2:無効な値の混入を防げる
Section titled “メリット2:無効な値の混入を防げる”関数の引数に Weekday 型を指定すれば、「1〜7以外の謎の数字」や「想定外の文字列」が渡されるのを防ぎ、プログラムの安全性が高まります。
メリット3:反復処理(イテレーション)が簡単
Section titled “メリット3:反復処理(イテレーション)が簡単”列挙型は for ループで簡単に回すことができます。ドロップダウンリストの選択肢を生成する際などに非常に便利です。
for day in Weekday: print(day.name, day.value)# MONDAY 1# TUESDAY 2# ...3. 便利な機能:auto()
Section titled “3. 便利な機能:auto()”列挙型の値そのものには意味がなく、「それぞれが重複しない一意の値であれば何でもいい」というケースは多々あります。その場合は auto() 関数を使うと、値を自動で割り振ってくれます。
from enum import Enum, auto
class OrderStatus(Enum): PENDING = auto() # 自動的に 1 SHIPPED = auto() # 自動的に 2 DELIVERED = auto() # 自動的に 3
print(OrderStatus.SHIPPED.value) # 出力: 24. 特殊な列挙型:IntEnum
Section titled “4. 特殊な列挙型:IntEnum”通常の Enum で定義したメンバーは、そのままでは整数(int)と比較することができません(Weekday.MONDAY == 1 は False になります)。
もし、既存のシステムとの互換性などの理由で、整数としても扱える列挙型が必要な場合は、IntEnum を継承して定義します。
from enum import IntEnum
class Priority(IntEnum): LOW = 10 NORMAL = 20 HIGH = 30
# IntEnumなら数値としての比較が可能print(Priority.HIGH > Priority.LOW) # 出力: Trueprint(Priority.NORMAL == 20) # 出力: Trueenum モジュールを活用することで、「マジックナンバー(意味不明な数字)」や「ハードコードされた文字列」を排除し、美しく堅牢なPythonコードを書くことができるようになります。