ゴミ箱の中のメモ帳

まだ見ぬ息子たちへ綴る手記

Pythonのenum型(列挙型)

先日Ubuntu12.04にPython3.4をインストールしたわけだけど、そのPython3.4にはいくつか便利な機能が追加されている。それはリリースノートを読んで欲しいところだが、その中でも異色になるのがenumの導入になる。

PHPRubyPerl等のLLに標準でenumが導入されたのは初めてではないだろうか。Pythonにも以前からenumを実現するモジュールが作成されていたし、RubyPerlにも同等のモジュールがある。だがこれがデフォルトに追加されるのは珍しい。

そして何よりも珍しいのは、C言語等でenumを利用している方は「enum型」として馴染みはあるかと思うが、PythonではEnumはクラスになる。

ということでそのenumについてどう気持ちがいいかまとめようとしたが、C言語など久しく書いていない上にまともに書いていないため気持ちよさがあまりわからない。ということで使い方をまとめておく。気持ちよさがわかるサンプルコードを募集中です。

パーフェクトPython (PERFECT SERIES 5)

パーフェクトPython (PERFECT SERIES 5)


まず、Enumは先に書いたように型ではなくクラスとして実装されている。Pythonに型を増やしても仕方がないというのがもちろんその理由かと思う。本当の理由はノートを読めば書いてあるかと思う。


最もシンプルな参考コードは以下になる。

import enum

class Cardsuit( enum.Enum):
SPADE = 1
CLUB = 2
HEART = 3
DIAMOND = 4

これはEnumクラスを継承してそのクラス内に列挙する方法だが、このシンプルな内容であれば関数型APIが用意されており以下のように書くことも出来る。

Cardsuit = enum.Enum( "Cardsuit", "SPADE CLUB HEART DIAMOND")

第一引数はEnumの名前になり、第二引数はメンバの名前を羅列した文字列になる。文字列はホワイトスペースで区切るかシーケンスにするということ。

Cardsuit = enum.Enum( "Cardsuit", "SPADE, CLUB, HEART, DIAMOND")

このようなカンマで区切っても問題ない。カンマ区切りのほうが実用的かと思う。

それぞれにはクラス継承のサンプルのように、1から4の整数が割り振られる。0オリジンではなく1オリジンになることに注意。


0オリジンやバラバラの数値を割り当てることももちろん出来る。

class Cardsuit( enum.Enum):
JORKER = 0
SPADE = 2
CLUB = 4
HEART = 6
DIAMOND = 8

一つのメンバに複数の値を設定することは出来ないが、複数のメンバに同じ値を設定することは出来る。

class Cardsuit( enum.Enum):
SPADE = 1
SPADE = 0
CLUB = 2
HEART = 3
DIAMOND = 4

これは出来ない。

class Cardsuit( enum.Enum):
JORKER = 0
SPADE = 1
SPADES = 1
CLUB = 2
CLUBS = 2
HEART = 3
HEARTS = 3
DIAMOND = 4
DIAMONDS = 4

これは出来る。

注意としては、同じ値の2つ目以降のメンバは一つ目のメンバのエイリアスになるということ。

len( Cardsuit)
[ suit for suit in Cardsuit]

としても重複する値のメンバは表示されない。重複する値のメンバも処理する必要がある場合は以下のように呼び出す。

len( Cardsuit.__members__)
[ suit for suit in Cardsuit.__members__]


もし重複した値を許容したくない場合にはユニークな値をチェックできる。

@enum.unique
class Cardsuit( enum.Enum):
JORKER = 0
SPADE = 1
SPADES = 1
CLUB = 2
HEART = 3
DIAMOND = 4

これはエラーとなる。


そして、一番上に書いた関数型APIでも自動的に値が割り振られるだけではなく自分で値の設定を行える。

Cardsuit = enum.Enum( "Cardsuit", [( "SPADE", 0), ( "CLUB", 1), ( "HEART", 2)])
Cardsuit = enum.Enum( "Cardsuit", { "SPADE": 0, "CLUB": 1, "HEART": 2})

このようにタプルを使った方法やディクショナリを使った方法がある。


そして最後に、もちろんenumなので継承したクラスの作成を行うことは出来ない。

class Base( enum.Enum):
SPADE = 1
CLUB = 2

class Alt( Base):
HEART = 3
DIAMOND = 4

これはエラーになる。


いやぁ、これはいいものだ。

公式マニュアルenumの説明に気合が入っていて面白い。最近は新機能の追加は少ないからマニュアルが充実してるのかな。

初めてのPython 第3版

初めてのPython 第3版

パーフェクトPython (PERFECT SERIES 5)

パーフェクトPython (PERFECT SERIES 5)

Pythonプロフェッショナルプログラミング

Pythonプロフェッショナルプログラミング

エキスパートPythonプログラミング

エキスパートPythonプログラミング