summer_tree_home

Check iOでPython3をマスターするぜっ

Python3.4のEnum(列挙型)を使ってみた

先日、Python3.4が正式リリースされたので、一番気になっていた Enum(列挙型)を使ってみた。
enum — Python 3.4.0 documentation(英語)

Enumを定義

enum.Enumを継承して定義する。

from enum import Enum

class Color(Enum):
    red = 1
    green = 2
    blue = 3

このように、属性の名前(name)と値(value)を定義していく。

値(value)はintに限らず、文字列やタプルでもよい。

class Color2(Enum):
	red = '#ff0000'
	green = '#00ff00'
	blue = '#0000ff'

class Color3(Enum):
	red = (255, 0, 0)
	green = (0, 255, 0)
	blue = (0, 0, 255)


もっとシンプルに書くこともできる。(namedtupleのように)

Color = Enum('Color', 'red green blue')

この場合、値(value)は前から順番に1,2,3..となる。(0からではなく1からスタート)

nameとvalueプロパティ

Enumのメンバーはnameとvalueプロパティを持つ。

>>> Color.red
<Color.red: 1>

>>> Color.red.name
'red'

>>> Color.red.value
1

nameやvalueから、メンバーを指定することもできる。

>>> Color(2)
<Color.green: 2>

>>> Color['blue']
<Color.blue: 3>

メソッド

メソッドやクラスメソッドを追加できる。

class Color(Enum):
    red = 1
    green = 2
    blue = 3

    # メンバーのメソッド (self=各メンバー)
    def to_japanese(self):
        return '赤緑青'[self.value - 1]

    # クラスメソッド
    @classmethod  
    def favorite_color(cls):
        return cls.blue

メソッドを使ってみる。

>>> Color.red.to_japanese()
'赤'

>>> Color.favorite_color()
<Color.blue: 3>

>>> Color.favorite_color().to_japanese()
'青'

イテレート

Enum型はイテレート可能。
forでループしたり、

>>> for c in Color:
...    print(c)

Color.red
Color.green
Color.blue

リストにキャストしたり。

>>> list(Color)
[<Color.red: 1>, <Color.green: 2>, <Color.blue: 3>]

その他

他に気になった点。

  • Enum型は、ハッシュ可能なので、辞書(dict)のキーにも使える。
  • 値を整数に限定した IntEnum というのもある。(ただ、通常は Enum を使えとも書いてある。)
  • 定義済みのEnumを継承して、後からメンバーを追加することはできない。
  • 別の名前で同じ値にすることも可能(値の重複)。ただし、最初のメンバー以外はエイリアスという扱いになり、イテレート時にでてこない。
  • __member__は、エイリアスも含めたすべてのメンバーが含まれた辞書。

 

何に使う?

今までに書いたコードで言えば、東西南北を、'N','E','W','S'などの文字列で定義していたのを、Enumにすることですっきりするかなと思う。あとは、曜日とか色名かな?

曜日だと、こんな感じだろうか?

from enum import Enum
from datetime import date

class DayOfWeek(Enum):
    Monday = 0
    Tuesday = 1
    Wednesday = 2
    Thursday = 3
    Friday = 4
    Saturday = 5
    Sunday = 6

    def weekday(self):
        return self.value

    def iso_weekday(self):
        return self.value + 1

    def to_japanese(self):
        return '月火水木金土日'[self.value]

    @property
    def shortname(self):
        return self.name[:3]

    @classmethod
    def from_date(cls, d):
        return cls(d.weekday())


w = DayOfWeek.from_date(date(2014, 3, 19))
print(w)                # DayOfWeek.Wednesday
print(w.name)           # 'Wednesday'
print(w.value)          # 2
print(w.weekday())      # 2
print(w.iso_weekday())  # 3
print(w.to_japanese())  # '水'
print(w.shortname)      # 'Wed'

おー、なんか面白い。