320
277

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

enum 超まとめ python3.11

Last updated at Posted at 2017-11-18

追記

本記事は当初python3.6 のenumについて書きました。

  • python3.7 からの機能は以下の通りです、大して変わってないです。
    https://qiita.com/ksato9700/items/35a0bdc04693b3b09757#enum
  • 3.8, 3.9, 3.10 が出ましたが、enumについては変更ないです。
  • 3.11 は色々更新がありました。str型と比較できるStrEnumの追加や、制約を検証できるverify()デコレータの追加が大きいです。

前置き

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を継承している。IntEnumと同様に 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 では上手くいかない場合のみに使うべきです; 例えば、整数定数を列挙型で置き換えるときや、他のシステムとの相互運用性を持たせたいときです。

参照元: https://docs.python.org/ja/3.6/library/enum.html

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

快適なenumライフを!

320
277
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
320
277

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?