基本
Pythonの列挙型enumは何かひとまとまりの定数を定義するときに便利な型で、Python3.4から導入されました。
例えば、ゲームのプログラムで今どの画面かを識別するために以下のような変数を定義したとします。
SCREEN_TITLE = 1 #タイトル画面 SCREEN_PLAYING = 2 #プレイ中画面 SCREEN_GAME_OVER = 3 #ゲームオーバー画面 SCREEN_TRANSITION = 4 #画面遷移中
このままでもプログラムできますが、もう少しまとめてあつかいたい、と考える人もいるでしょう。 また、ただの変数なのでうっかり書きかえないかも心配です。
これをenumを使えば、以下のように書き直せます。
from enum import Enum class Screen(Enum): TITLE = 1 PLAYING = 2 GAME_OVER = 3 TRANSITION = 4
使う時は
Screen.PLAYING
などとすれば参照できます。
比較するときはメンバー同士で行う必要があります。
print(Screen.TITLE == 1) print(Screen.TITLE == Screen.TITLE)
結果:
False True
Enumは他の型の値と直接比較できないので注意してください。 めんどうなようですが、こうなっているとせっかく定義したEnum型を使わずに手で直接値を指定してしまうという、いわゆるマジックナンバーの問題をある程度予防してくれるというメリットがあります。
必要であれば、後述のIntEum型なら整数との比較が可能です。
この記事では数値で定義しましたが、文字列で定義することも可能です。
また、これらは実質定数として扱えます。 例えば、
Screen.GAME_OVER = 2
とすると
Traceback (most recent call last): File "enumtest.py", line 10, in <module> Screen.GAME_OVER = 2 File "/usr/lib/python3.6/enum.py", line 363, in __setattr__ raise AttributeError('Cannot reassign members.') AttributeError: Cannot reassign members.
というような実行時エラーが出ます。
また、
screen = Screen.PLAYING print(screen)
とすると、
Screen.PLAYING
とクラスとメンバー名が出力されるのでデバッグの時にわかりやすくて便利です。
nameとvalueというプロパティを使えばメンバー名と値も参照できます。
print(Screen.GAME_OVER.name,Screen.GAME_OVER.value)
結果:
GAME_OVER 4
ループ処理もできます。 このとき、順番は定義順であることが保証されています。
for s in Screen: print(s)
結果:
Screen.TITLE Screen.PLAYING Screen.GAME_OVER Screen.TRANSITION
となります。
このようにenumを使うと定数をまとめてあつかいやすくなります。
さらに以下のような便利な機能があります。
auto
Python3.6から自動で番号をつけてくれるautoという関数が加わりました。
from enum import Enum, auto class Screen(Enum): TITLE = auto() PLAYING = auto() GAME_OVER = auto() TRANSITION = auto()
とすれば自動で番号をつけてくれます。
例えば上の例でタイトル画面の前にというロード画面を付け加えたい、順番的にできればそれを表す定数は1にしたい、となったときに、手で番号をつけると今までの定義を全て手で1ずらさねばなりません。
class Screen(Enum): LOADING = 1 TITLE = 2 #ここから下全て1ずらした PLAYING = 3 GAME_OVER = 4 TRANSITION = 5
enumのメンバー数が多いと編集が大変になります。 autoを使っておけば自動で番号をつけてくれるので「LOADING = auto()」という一行を付け加えるだけでよく、手間が省けます。
class Screen(Enum): LOADING = auto() #この行だけ増やした TITLE = auto() PLAYING = auto() GAME_OVER = auto() TRANSITION = auto()
また、enum型は値が一意になる事は保証していません。 次のようなコードは問題なく実行されます。
class Test(Enum): TEST1 = 1 TEST2 = 1 TEST3 = 1
しかし、実際には一意な値をつけたいときが多いでしょう。 手で定義するとどうしても書き間違いの可能性が出てきます。 その時は「@unique」というデコレータを使えば一意であることが保証されます。
@unique class Test(Enum): TEST1 = 1 TEST2 = 1 TEST3 = 1
とすると、実行時エラーになります。
しかし、autoを使っておけば、自動的に値は一意になります。 とりあえず値はなんでもいいという場合にはautoを使うのがおすすめです。
autoを使いつつ、特定の値を同じにしたければ以下のようにします。
class Test(Enum): TEST1 = auto() TEST2 = auto() TEST3 = auto() TEST2_ALT = TEST2 print(Test.TEST2_ALT,Test.TEST2_ALT.value)
結果:
Test.TEST2 2
IntEnum
Enumとほぼ同じですが、整数や他のIntEnum型との直接の比較が可能になっています。
ほとんどの場合Enumで十分ですが、外部から入力された値に名前をつけたい、他のプログラムとデータのやり取りをするときに独自の名前をつけたい、計算結果に名前をつけたい、といった場合に、その値が整数なら簡単に比較できるようになるので便利です。
IntFlagとFlag
Enumにビット演算子を適用可能にしてフラグとして使いやすくした物です。 ここに書くと長くなるのでページを分けてPython/FlagとIntFlagで説明しています。
Page Info | |
---|---|
Page Name : | Python/列挙型 |
Page aliases : | None |
Page owner : | njf |
Can Read | |
Groups : | All visitors |
Users : | All visitors |
Can Edit | |
Groups : | All visitors |
Users : | All visitors |