Python PR

【Python】列挙型を使う方法を解説【Enum・IntEnum】

記事内に商品プロモーションを含む場合があります

この記事では、Pythonで列挙型を使う方法を解説します。

列挙型(Enum)とは、抽象データを定義するための機能で、性別などのマジックナンバーを使ってしまいそうな値を型として定義することができます。

例えば、以下のようなコードを見たことありませんか?

# 性別を表す変数
gender = 0

if gender == 0:
    print('男性')
else:
    print('女性')

このコードは、genderの値が「0ならば男性」「0以外ならば女性」と出力するコードですが、値自体にはなんの関連性もなく、人によっては「0 = 女性」「1 = 男性」と定義するかもしれません。

このようなコードは、直感的にわかりずらく思い込みや勘違いから無用な問題を引き起こす可能性があり、あまりいいコードとは言えません。

そこで 列挙型の出番です!

列挙型は、Python 3.4から追加されました

列挙型(Enum)を使う

列挙型は、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):
    ...

クラス内には、列挙型の値としてnamevalueを定義します。

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クラス]

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

auto

enumモジュールのauto()valueに指定することで適切な値を取得できる。

Python 3.6 で追加

EnumIntEnumvalueに指定した場合、最後の値に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 で追加されました。

それでは今回の内容はここまでです!ではまたどこかで〜( ・∀・)ノ