基本的には推奨されない書き方のようですが、使ってみて便利だったのでメモします。
環境
- Python
- 3.12
実装
int
等のプリミティブな型の継承は次のとおりです。
from enum import Enum class IntInheritEnum(int, Enum): ID = 1 # 列挙型ではなく、intとして振舞うため1にアクセスできる IntInheritEnum.ID # 本来のアクセス方法 IntInheritEnum.ID.value
ただし、自作クラス等は継承できません。metaclass
の競合が起きるため、クラスで定義したかったものがあれば、namedtuple
等を使用するとアクセスしやすくなります。
# metaclassの競合が起きるから、継承できない # E TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases # class DummyUser(User, Enum): # ADMIN = User(name="admin", email="admin@example.com") DummyValue = namedtuple('DummyValue', ['name', 'email']) class DummyUser(Enum): ADMIN = DummyValue("admin", "admin@example.com") # こうやって各項目にアクセスする DummyUser.ADMIN.value.name DummyUser.ADMIN.value.email
推奨されない理由
型が違うまま計算できてしまうため、誤った処理をしかねないのが推奨されない原因のようです(ChatGPTより)
# 継承していなければエラーとなる # 継承しているのでエラーならない result: int = IntInheritEnum.ID + 10 # 型が違うのに計算できてしまうのは確かに違和感がある def add(num1: int, num2: IntInheritEnum): return num1 + num2
ユースケース
indexでアクセスしたい時にintを継承したenumを使用することで簡潔にアクセスできる。
JOINしたテーブルの取得結果の操作や、pandas
でCSVを読み込んだ時の列をenumを使用することで列名として代用できます。
本来はもっと人間に読みやすい定義方法もあると思うのですが、わかりませんでした。namedXXX
を駆使すれば行けそうだとは思っていますが…。
ソースコード
終わりに
毎回.value
でアクセスしていた処理が無くなったので、コード自体は読みやすくなりました。
少しずつ、リーダブルなコードが書けるようにしたいですね。