CやVBAのEnum
CやVBAのEnumでは、各メンバの値は指定してもしなくてもよく、指定しない場合は一つ前のメンバの数値+1になります。先頭のメンバは値を指定しないと0になります。
個人的には、VBAでCSVなどの入力ファイルを扱うときに、ファイルのフィールドを識別するためにEnum型が便利なのでよく使っていたりします。例えば次のような感じです。
Public Enum FieldID
OrderNo = 1
CustomerNo
PurchaseDate
ProductID = 10
Price
Units
Amount
End Enum
この例のように、要素の数が少ない場合はありがたみが分からないかもしれませんが、数十列もあるファイルのフィールドを定義してる場合、列の追加や削除があってもすべてのメンバに番号の振りなおす必要がないので便利です。
Python3.6ではEnum型に自動で値をつける機能が追加されたので、同じようにできるのか試してみました。
PythonのEnum
Pythonには、バージョン3.4でEnumクラスが標準ライブラリに追加されました。PythonのEnumについては、こちらの記事でよくまとめられてます。
Enumライブラリのドキュメントにあるように、Python3.6ではEnumに自動的に値を付けるための、=auto()
という表現が追加されました。(実際にはauto
はクラスで、そのコンストラクタを呼んでいます。)
先程のVBAのコードと同じことを試してみました。
from enum import IntEnum, auto
class Field(IntEnum):
OrderNo = 1
CustomerNo = auto()
PurchaseDate = auto()
ProductID = 10
Price = auto()
Units = auto()
Amount = auto()
for elm in Field:
print(elm, int(elm))
実行結果は、
Field.OrderNo 1
Field.CustomerNo 2
Field.PurchaseDate 3
Field.ProductID 10
Field.Price 11
Field.Units 12
Field.Amount 13
となり、auto()
と記述する必要はありますが、CやVBAのように自動でインクリメントするようです。ただ、最初のメンバを=auto()
とすると、0ではなく1になります。
ただし、ライブラリのドキュメントに注意書きがあり、このインクリメントは実装依存とのことです。この振る舞いを恒久的にするには、自分でauto()
の挙動を定義する必要があります。
auto()
の返す値は、_generate_next_value_
メソッドでカスタマイズ可能なので、IntEnum
を継承したクラスAutoIntoEnum
を作成して、_generate_next_value_
を自分で定義しておきます。
from enum import IntEnum, auto
class AutoIntEnum(IntEnum):
def _generate_next_value_(name, start, count, last_values):
for last_value in reversed(last_values):
try:
return last_value + 1
except TypeError:
pass
else:
return start
class Field(AutoIntEnum):
OrderNo = auto()
CustomerNo = auto()
PurchaseDate = auto()
ProductID = 10
Price = auto()
Units = auto()
Amount = auto()
for elm in Field:
print(elm, int(elm))
これで_generate_next_value_
の実装が変わってもOKです。
_generate_next_value_
の中身は、Enumクラスのコードからそのままコピペしました。