この記事では、Pythonで列挙型を使う方法を解説します。
列挙型(Enum)とは、抽象データを定義するための機能で、性別などのマジックナンバーを使ってしまいそうな値を型として定義することができます。
例えば、以下のようなコードを見たことありませんか?
# 性別を表す変数
gender = 0
if gender == 0:
print('男性')
else:
print('女性')
このコードは、gender
の値が「0ならば男性」「0以外ならば女性」と出力するコードですが、値自体にはなんの関連性もなく、人によっては「0 = 女性」「1 = 男性」と定義するかもしれません。
このようなコードは、直感的にわかりずらく思い込みや勘違いから無用な問題を引き起こす可能性があり、あまりいいコードとは言えません。
そこで 列挙型の出番です!
列挙型は、enum
モジュールのEnum
クラスを継承させることで使用できます。
先ほどの性別を列挙型にすると、以下のようになります。
※ 今回は分かりやすいように日本語で定義しました。
from enum import Enum
class Gender(Enum):
男性 = 0
女性 = 1
これでGender
という性別を表す列挙型が定義できました。
では、列挙型を用いて最初のコードを書き直してみましょう!
すると、以下のようになります。
gender = Gender.男性
if gender == Gender.男性:
print('男性')
else:
print('女性')
上記コードでは、マジックナンバーを使わずに定義でき、見ただけで男性を指定していることがわかります。このように、列挙型を使うことで抽象的な概念を型として定義することができます。
それでは、列挙型の定義方法や使い方をもう少し詳しく見ていきましょう!
列挙型は、enum
モジュールのEnum
クラスを使って定義します。enum
モジュールは、標準ライブラリなのでインポートするだけで使えます。
from enum import Enum
インポートしたEnum
クラスから派生クラスを定義します。
from enum import Enum
class クラス名(Enum):
...
クラス内には、列挙型の値としてname
とvalue
を定義します。
from enum import Enum
class クラス名(Enum):
name1 = value1
name2 = value2
・
・
・
nameN = valueN
変数名がname
、値がvalue
として扱われます。
次に、列挙型の呼び出し方法を見ていきましょう!
通常の呼び出し
print(Gender.男性)
# Gender.男性
nameのみの呼び出し
print(Gender.男性.name)
# 男性
valueのみの呼び出し
print(Gender.男性.value)
# 0
valueからの呼び出し
print(Gender(0))
# Gender.男性
for文を使った呼び出し
for g in Gender:
print(g)
# Gender.男性
# Gender.女性
列挙型は比較されることが多いオブジェクトです。
==
print(Gender.男性 == Gender.男性)
# True
print(Gender.男性 == Gender.女性)
# False
!=
print(Gender.男性 != Gender.男性)
# False
print(Gender.男性 != Gender.女性)
# True
is
print(Gender.男性 is Gender.男性)
# True
print(Gender.男性 is Gender.女性)
# False
大なり小なり
print(Gender.男性 < Gender.男性) # TypeError
print(Gender.男性 > Gender.女性) # TypeError
IntEnum
クラスなら可能。
数値との比較
数値と比較すると False
が返される。
print(Gender.男性 == 0)
# False
print(Gender.女性 == 0)
# False
数値と比較したいなら IntEnum
クラスを使う。
列挙型には、通常のクラスと同様にメソッドを定義することもできます。呼び出し時にインスタンス化する必要はありません。
from enum import Enum
class Gender(Enum):
男性 = 0
女性 = 1
# 列挙型のメソッド
def get_name(self):
return self.name
print(Gender.男性.get_name())
# 男性
print(Gender.女性.get_name())
# 女性
コンストラクタを定義することもできます。定義した場合は、列挙型の値がインスタンス変数に渡されます。
from enum import Enum
class Gender(Enum):
男性 = 0
女性 = 1
# 列挙型のコンストラクタ
def __init__(self, num):
self.num = num
print(Gender.男性.num)
# 0
print(Gender.女性.num)
# 1
以下のように複数の値でも可能です。
from enum import Enum
class Test(Enum):
NUMS1 = (0, 1, 2)
NUMS2 = (3, 4, 5)
def __init__(self, num1, num2, num3):
self.num1 = num1
self.num2 = num2
self.num3 = num3
print(Test.NUMS1.num1) # 0
print(Test.NUMS1.num2) # 1
print(Test.NUMS1.num3) # 2
print(Test.NUMS2.num1) # 3
print(Test.NUMS2.num2) # 4
print(Test.NUMS2.num3) # 5
なんかちょっと違和感がありますね...。
IntEnum
クラスは、Enum
クラスとあまり違いはありませんが、整数と比較ができるようになっています。
from enum import IntEnum
class Gender(IntEnum):
男性 = 0
女性 = 1
print(Gender.男性 == 0)
# True
print(Gender.女性 == 0)
# False
また、異なるIntEnum
型とも比較可能です。
from enum import IntEnum
class Gender(IntEnum):
男性 = 0
女性 = 1
class Test(IntEnum):
NUM1 = 0
NUM2 = 1
print(Gender.男性 == Test.NUM1)
# True
print(Gender.男性 == Test.NUM2)
# False
さらに、Int
が頭に付いているだけあって整数として扱える場面が増えています。
print(int(Gender.男性))
# 0
nums = [1, 2, 3]
print(nums[Test.NUM1])
# 1
print(abs(Test.NUM1))
# 0
enum
モジュールのauto()
をvalue
に指定することで適切な値を取得できる。
Enum
、IntEnum
のvalue
に指定した場合、最後の値に1を加えたものになる。
from enum import auto, Enum
class MyEnum(Enum):
name1 = auto()
name2 = auto()
name3 = auto()
print(MyEnum.name1.value)
print(MyEnum.name2.value)
print(MyEnum.name3.value)
実行結果
1
2
3
初期値を決めたい場合は、最初だけ明示的に値を指定する。
from enum import auto, Enum
class MyEnum(Enum):
name1 = 100
name2 = auto()
name3 = auto()
print(MyEnum.name1.value)
print(MyEnum.name2.value)
print(MyEnum.name3.value)
実行結果
100
101
102
この記事では、Pythonの列挙型の使い方について解説しました。
Enum
クラスを継承して使うIntEnum
クラスを使う列挙型を使うことでマジックナンバーを減らすことができます。使える場面があったらじゃんじゃん使っていきましょう!
また、フラグを扱うためのクラスも Python 3.6 で追加されました。
それでは今回の内容はここまでです!ではまたどこかで〜( ・∀・)ノ