Edited at

enum 超まとめ python3.7

More than 1 year has passed since last update.


追記

本記事は当初python3.6 のenumについて書きましたが、python3.7が出たので3.6との差分が書いてあるリンクを載せておきます。大して変わってないです。

https://qiita.com/ksato9700/items/35a0bdc04693b3b09757#enum



前置き

enum の機能自体は3.4から(わりと遅いな...?)ありますが3.6になってから追加機能が加えられています。

そこで改めてpython のenum全体をざらっとまとめる記事を書いてみたいと思いました。


目次


  • enum概要

  • 機能


    • Enum クラス

    • IntEnum クラス

    • auto 関数 ※python3.6から

    • Flag クラス ※python3.6から

    • IntFlag クラス ※python3.6から



  • まとめ


enum概要

enumはenumerationの略で列挙型とも言われ、多くの言語で採用されている。

enumの概要や各言語のenumの簡単な例はwikipedia でまとまってたのでenum自体初めてという人参照するとよいかも。

https://ja.wikipedia.org/wiki/%E5%88%97%E6%8C%99%E5%9E%8B


機能


Enum クラス

最初は最も基本的なenumであるEnumクラス。説明するよりコードを見たほうが早い。

from enum import Enum

class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3

def print_color(color):
if color == Color.RED:
print('Color is red')
elif color == Color.GREEN:
print('Color is green')
elif color == Color.BLUE:
print('Color is blue')
else:
print('not Color enum')

if __name__ == '__main__':
print_color(Color.BLUE) # Color is blue
print_color(1) # not Color enum
print(Color) # <enum 'Color'>
print(Color(1)) # Color.RED
print(Color.RED == Color.RED) # True
print(Color.RED == Color.GREEN) # False
for color in Color:
print(color) # Color.RED\nColor.GREEN\nColor.BLUE

注目ポイントは Color(1) と数字で指定するとそれに対応した値(Color.RED)が返ってくることである。

しかし、 print_color(1) とすると、 print('not Color enum') が実行されることから、 int型とenumの比較はできない仕様になってい ることが分かる。

また、 for color in Color: のように for文で回せる。定義順(RED -> GREEN -> BLUE)で回る。


IntEnum クラス

IntEnumクラスはEnum クラスとintのサブクラスになっている。IntEnumのメンバーは int型と比較することができる。 違いはそれだけ。

from enum import IntEnum

class Color(IntEnum):
RED = 1
GREEN = 2
BLUE = 3

if __name__ == '__main__':
print_color(Color.BLUE) # Color is blue
print_color(1) # Color is red
print(int(Color.RED)) # 1

print_color 関数は前回と同じなので省略。


auto 関数

python3.6で追加された機能。

これまでRED, GREEN, BLUE などのメンバーに直接値を指定していたが、これを自動で値を割り振るのが auto 関数である。Enum, IntEnum, Flag, IntFlag のどれにも適用可能。

from enum import IntEnum, auto

class Color(IntEnum):
RED = auto()
GREEN = auto()
BLUE = auto()

if __name__ == '__main__':
print(int(Color.RED)) # 1
print(int(Color.GREEN)) # 2
print(int(Color.BLUE)) # 3

enumのメンバーの実際の値が何かというのは関心がないことが普通だ。そういった場合は問答無用で auto 関数を使うべきだと思う。

ちなみにこの場合、RED だけ RED = 10 にして、残りは auto() にすると、10からの連番がふられるようになる。


Flag クラス

python3.6で追加された機能。

Enumクラスの機能に加え、 Flag メンバーはビット演算子 (&, |, ^, ~) を使って組み合わせられる。

メンバの値には auto 関数を使うことが推奨されている。

from enum import Flag, auto

class Color(Flag):
RED = auto()
GREEN = auto()
BLUE = auto()
PURPLE = RED | BLUE
WHITE = RED | GREEN | BLUE

def print_color(color):
if color == Color.RED:
print('Color is red')
elif color == Color.GREEN:
print('Color is green')
elif color == Color.BLUE:
print('Color is blue')
elif color == Color.PURPLE:
print('Color is purple')
elif color == Color.WHITE:
print('Color is white')
else:
print('not defined')

if __name__ == '__main__':
print_color(Color.BLUE) # Color is blue
print_color(Color.PURPLE) # Color is purple
print_color(Color.RED | Color.BLUE) # Color is purple
print_color(Color.RED | Color.GREEN) # not defined
print_color(Color.WHITE) # Color is white
print_color(Color.RED | Color.GREEN | Color.BLUE) # Color is white

このような使い方が可能になる。使ったことがない(使うシーンが思いつかない)ので実用性はあまりわからない。


IntFlag クラス

python3.6で追加された機能。

Flag の int 版である。IntEnumと同じく、intを継承している。IntNumと同様に int型と比較することができる。

from enum import IntFlag, auto

class Color(IntFlag):
RED = auto()
GREEN = auto()
BLUE = auto()
PURPLE = RED | BLUE
WHITE = RED | GREEN | BLUE

if __name__ == '__main__':
print(int(Color.RED)) # 1 ※2進数だと 1
print(int(Color.GREEN)) # 2 ※2進数だと 10
print(int(Color.BLUE)) # 4 ※2進数だと 100
print(int(Color.PURPLE)) # 5 ※2進数だと 101
print(int(Color.WHITE)) # 7 ※2進数だと 111


まとめ

いかがだったでしょうか。python3.6になってから auto 関数ができてEnumの書き方が楽になった感じがありますね。

また、Flag やIntFlag などの特殊な使い方ができるenumも用意されていて面白いです。

で、結局これらのうちどれを使えばいいの?と思うと思いますが、公式ドキュメントにこう書かれてあります。


注釈 ほとんどの新しいコードでは、 Enum と Flag が強く推奨されます。 というのは、 IntEnum と IntFlag は (整数と比較でき、従って推移的に他の無関係な列挙型と比較できてしまうことにより) 列挙型の意味論的な約束に反するからです。 IntEnum と IntFlag は、 Enum や Flag では上手くいかない場合のみに使うべきです; 例えば、整数定数を列挙型で置き換えるときや、他のシステムとの相互運用性を持たせたいときです。


普通はEnum, Flagを使いましょう、どうしても整数を使いたいときはIntEnum, IntFlagを使いましょうとのことです。また Enumでも Flag でも auto 関数を使うのが良いでしょう。

快適なenumライフを!