Help us understand the problem. What is going on with this article?

Python3.6のEnumに自動で値を付けるautoを試す

More than 1 year has passed since last update.

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クラスのコードからそのままコピペしました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away