"enum" --- 列挙型のサポート
***************************

バージョン 3.4 で追加.

**ソースコード:** Lib/enum.py

======================================================================

列挙型は、一意の定数値に束縛された識別名 (メンバー) の集合です。列挙型
の中でメンバーの同一性を比較でき、列挙型自身でイテレートが可能です。

注釈:

  Enumメンバーは大文字/小文字？Enumクラス群は定数を表現するために使わ
  れるため、列挙型のメンバーの名前にはUPPER_CASEを使うことを推奨します
  。本ページのドキュメントのサンプルでもそのスタイルを採用します。


モジュールコンテンツ
====================

このモジュールでは一意の名前と値の集合を定義するのに使用できる 4 つの
列挙型クラス "Enum", "IntEnum", "Flag", "IntFlag" を定義しています。
このモジュールはデコレータの "unique()" とヘルパークラスの "auto" も定
義しています。

class enum.Enum

   列挙型定数を作成する基底クラスです。もうひとつの構築構文については
   機能 API を参照してください。

class enum.IntEnum

   "int" のサブクラスでもある列挙型定数を作成する基底クラスです。

class enum.IntFlag

   列挙型定数を作成する基底クラスで、ビット演算子を使って組み合わせら
   れ、その結果も "IntFlag" メンバーになります。 "IntFlag" は "int" の
   サブクラスでもあります。

class enum.Flag

   列挙型定数を作成する基底クラスで、ビット演算を使って組み合わせられ
   、その結果も "IntFlag" メンバーになります。

enum.unique()

   一つの名前だけがひとつの値に束縛されていることを保証する Enum クラ
   スのデコレーターです。

class enum.auto

   インスタンスはそれぞれ、適切な値で置き換えられます。値は、1からはじ
   まります。

バージョン 3.6 で追加: "Flag", "IntFlag", "auto"


Enum の作成
===========

列挙型は読み書きが容易になるよう "class" 文を使って作成します。もうひ
とつの作成方法は 機能 API で説明しています。列挙型は以下のように
"Enum" のサブクラスとして定義します:

   >>> from enum import Enum
   >>> class Color(Enum):
   ...     RED = 1
   ...     GREEN = 2
   ...     BLUE = 3
   ...

注釈:

  列挙型のメンバー値メンバー値は何であっても構いません: "int", "str"
  などなど。 正確な値が重要でない場合は、 "auto" インスタンスを使って
  おくと、適切な値が選ばれます。 "auto" とそれ以外の値を混ぜて使う場合
  は注意する必要があります。

注釈:

  用語

  * クラス "Color" は *列挙型* (または *Enum*) です

  * 属性 "Color.RED", "Color.GREEN" などは *列挙型のメンバー* (または
    *Enum メンバー*) で、機能的には定数です。

  * 列挙型のメンバーは *名前* と *値* を持ちます ("Color.RED" の名前は
    "RED" 、 "Color.BLUE" の値は "3" など。)

注釈:

  Enum の作成に "class" 文を使用するものの、Enum は通常の Python クラ
  スではありません。詳細は Enum はどう違うのか? を参照してください。

列挙型のメンバーは人が読める文字列表現を持ちます:

   >>> print(Color.RED)
   Color.RED

...その一方でそれらの "repr" はより多くの情報を持っています:

   >>> print(repr(Color.RED))
   <Color.RED: 1>

列挙型メンバーの *データ型* はそれが所属する列挙型になります:

   >>> type(Color.RED)
   <enum 'Color'>
   >>> isinstance(Color.GREEN, Color)
   True
   >>>

Enum メンバーは自身の名前を持つだけのプロパティも持っています:

   >>> print(Color.RED.name)
   RED

列挙型は定義順でのイテレーションをサポートしています:

   >>> class Shake(Enum):
   ...     VANILLA = 7
   ...     CHOCOLATE = 4
   ...     COOKIES = 9
   ...     MINT = 3
   ...
   >>> for shake in Shake:
   ...     print(shake)
   ...
   Shake.VANILLA
   Shake.CHOCOLATE
   Shake.COOKIES
   Shake.MINT

列挙型のメンバーはハッシュ化可能なため、辞書や集合で使用できます:

   >>> apples = {}
   >>> apples[Color.RED] = 'red delicious'
   >>> apples[Color.GREEN] = 'granny smith'
   >>> apples == {Color.RED: 'red delicious', Color.GREEN: 'granny smith'}
   True


列挙型メンバーおよびそれらの属性へのプログラム的アクセス
========================================================

プログラム的にメンバーに番号でアクセスしたほうが便利な場合があります (
すなわち、プログラムを書いている時点で正確な色がまだわからなく、
"Color.RED" と書くのが無理な場合など)。 "Enum" ではそのようなアクセス
も可能です:

   >>> Color(1)
   <Color.RED: 1>
   >>> Color(3)
   <Color.BLUE: 3>

列挙型メンバーに *名前* でアクセスしたい場合はアイテムとしてアクセスで
きます:

   >>> Color['RED']
   <Color.RED: 1>
   >>> Color['GREEN']
   <Color.GREEN: 2>

列挙型メンバーの "name" か "value" が必要な場合:

   >>> member = Color.RED
   >>> member.name
   'RED'
   >>> member.value
   1


列挙型メンバーと値の重複
========================

同じ名前の列挙型メンバーを複数持つことはできません:

   >>> class Shape(Enum):
   ...     SQUARE = 2
   ...     SQUARE = 3
   ...
   Traceback (most recent call last):
   ...
   TypeError: Attempted to reuse key: 'SQUARE'

ただし、複数の列挙型メンバーが同じ値を持つことはできます。同じ値を持つ
2 つのメンバー A および B (先に定義したのは A) が与えられたとき、B は
A の別名になります。A および B を値で調べたとき、A が返されます。B を
名前で調べたとき、A が返されます:

   >>> class Shape(Enum):
   ...     SQUARE = 2
   ...     DIAMOND = 1
   ...     CIRCLE = 3
   ...     ALIAS_FOR_SQUARE = 2
   ...
   >>> Shape.SQUARE
   <Shape.SQUARE: 2>
   >>> Shape.ALIAS_FOR_SQUARE
   <Shape.SQUARE: 2>
   >>> Shape(2)
   <Shape.SQUARE: 2>

注釈:

  すでに定義されている属性と同じ名前のメンバー (一方がメンバーでもう一
  方がメソッド、など) の作成、あるいはメンバーと同じ名前の属性の作成は
  できません。


番号付けの値が同一であることの確認
==================================

デフォルトでは、前述のように複数の名前への同じ値の定義は別名とすること
で許されています。この挙動を望まない場合、以下のデコレーターを使用する
ことで各値が列挙型内で一意かどうか確認できます:

@enum.unique

列挙型専用の "class" デコレーターです。列挙型の "__members__" に別名が
ないかどうか検索します; 見つかった場合、"ValueError" が詳細情報ととも
に送出されます:

   >>> from enum import Enum, unique
   >>> @unique
   ... class Mistake(Enum):
   ...     ONE = 1
   ...     TWO = 2
   ...     THREE = 3
   ...     FOUR = 3
   ...
   Traceback (most recent call last):
   ...
   ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE


値の自動設定を使う
==================

正確な値が重要でない場合、 "auto" が使えます:

   >>> from enum import Enum, auto
   >>> class Color(Enum):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> list(Color)
   [<Color.RED: 1>, <Color.BLUE: 2>, <Color.GREEN: 3>]

その値は "_generate_next_value_()" によって選ばれ、この関数はオーバー
ライドできます:

   >>> class AutoName(Enum):
   ...     def _generate_next_value_(name, start, count, last_values):
   ...         return name
   ...
   >>> class Ordinal(AutoName):
   ...     NORTH = auto()
   ...     SOUTH = auto()
   ...     EAST = auto()
   ...     WEST = auto()
   ...
   >>> list(Ordinal)
   [<Ordinal.NORTH: 'NORTH'>, <Ordinal.SOUTH: 'SOUTH'>, <Ordinal.EAST: 'EAST'>, <Ordinal.WEST: 'WEST'>]

注釈:

  デフォルトの "_generate_next_value_()" メソッドの目的は、最後に提供
  した "int" の次から順々に "int" を提供することですが、この動作は実装
  詳細であり変更される可能性があります。

注釈:

  "_generate_next_value_()" メソッドは他のメンバーよりも前に定義される
  必要があります。


イテレーション
==============

列挙型のメンバーのイテレートは別名をサポートしていません:

   >>> list(Shape)
   [<Shape.SQUARE: 2>, <Shape.DIAMOND: 1>, <Shape.CIRCLE: 3>]

特殊属性 "__members__" は読み出し専用で、順序を保持した、対応する名前
と列挙型メンバーのマッピングです。これには別名も含め、列挙されたすべて
の名前が入っています。

   >>> for name, member in Shape.__members__.items():
   ...     name, member
   ...
   ('SQUARE', <Shape.SQUARE: 2>)
   ('DIAMOND', <Shape.DIAMOND: 1>)
   ('CIRCLE', <Shape.CIRCLE: 3>)
   ('ALIAS_FOR_SQUARE', <Shape.SQUARE: 2>)

属性 "__members__" は列挙型メンバーへの詳細なアクセスに使用できます。
以下はすべての別名を探す例です:

   >>> [name for name, member in Shape.__members__.items() if member.name != name]
   ['ALIAS_FOR_SQUARE']


比較
====

列挙型メンバーは同一性を比較できます:

   >>> Color.RED is Color.RED
   True
   >>> Color.RED is Color.BLUE
   False
   >>> Color.RED is not Color.BLUE
   True

列挙型の値の順序の比較はサポートされて *いません*。Enum メンバーは整数
ではありません (IntEnum を参照してください):

   >>> Color.RED < Color.BLUE
   Traceback (most recent call last):
     File "<stdin>", line 1, in <module>
   TypeError: '<' not supported between instances of 'Color' and 'Color'

ただし等価の比較は定義されています:

   >>> Color.BLUE == Color.RED
   False
   >>> Color.BLUE != Color.RED
   True
   >>> Color.BLUE == Color.BLUE
   True

非列挙型の値との比較は常に不等となります (繰り返しになりますが、
"IntEnum" はこれと異なる挙動になるよう設計されています):

   >>> Color.BLUE == 2
   False


列挙型で許されるメンバーと属性
==============================

上述の例では列挙型の値に整数を使用しています。整数の使用は短くて使いや
すい (そして 機能 API でデフォルトで提供されています) のですが、厳密に
は強制ではありません。ほとんどの事例では列挙型の実際の値が何かを気にし
ていません。しかし、値が重要で *ある* 場合、列挙型は任意の値を持つこと
ができます。

列挙型は Python のクラスであり、通常どおりメソッドや特殊メソッドを持つ
ことができます:

   >>> class Mood(Enum):
   ...     FUNKY = 1
   ...     HAPPY = 3
   ...
   ...     def describe(self):
   ...         # self is the member here
   ...         return self.name, self.value
   ...
   ...     def __str__(self):
   ...         return 'my custom str! {0}'.format(self.value)
   ...
   ...     @classmethod
   ...     def favorite_mood(cls):
   ...         # cls here is the enumeration
   ...         return cls.HAPPY
   ...

上記の結果が以下のようになります:

   >>> Mood.favorite_mood()
   <Mood.HAPPY: 3>
   >>> Mood.HAPPY.describe()
   ('HAPPY', 3)
   >>> str(Mood.FUNKY)
   'my custom str! 1'

何が許されているかのルールは次のとおりです。先頭と末尾が 1 個のアンダ
ースコアの名前は列挙型により予約されているため、使用できません。列挙型
内で定義されたその他すべての名前は、その列挙型のメンバーとして使用でき
ます。特殊メソッド ("__str__()", "__add__()" など) と、メソッドを含む
デスクリプタ(記述子)、 "_ignore_" に記載されている変数名は例外です。

注意: 列挙型で "__new__()" および/または "__init__()" を定義した場合、
列挙型メンバーに与えられた値はすべてこれらのメソッドに渡されます。例
Planet を参照してください。


Enumのサブクラス化の制限
========================

新しい "Enum" クラスは、ベースのEnumクラスを1つ、具象データ型を1つ、複
数の "object" ベースのミックスインクラスが許容されます。これらのベース
クラスの順序は次の通りです:

   class EnumName([mix-in, ...,] [data-type,] base-enum):
       pass

列挙型のサブクラスの作成はその列挙型にメンバーが一つも定義されていない
場合のみ行なえます。従って以下は許されません:

   >>> class MoreColor(Color):
   ...     PINK = 17
   ...
   Traceback (most recent call last):
   ...
   TypeError: Cannot extend enumerations

以下のような場合は許されます:

   >>> class Foo(Enum):
   ...     def some_behavior(self):
   ...         pass
   ...
   >>> class Bar(Foo):
   ...     HAPPY = 1
   ...     SAD = 2
   ...

メンバーが定義された列挙型のサブクラス化を許可すると、いくつかのデータ
型およびインスタンスの重要な不変条件の違反を引き起こします。とはいえ、
それが許可されると、列挙型のグループ間での共通の挙動を共有するという利
点もあります。 (OrderedEnum の例を参照してください。)


Pickle 化
=========

列挙型は pickle 化と unpickle 化が行えます:

   >>> from test.test_enum import Fruit
   >>> from pickle import dumps, loads
   >>> Fruit.TOMATO is loads(dumps(Fruit.TOMATO))
   True

通常の pickle 化の制限事項が適用されます: pickle 可能な列挙型はモジュ
ールのトップレベルで定義されていなくてはならず、unpickle 化はモジュー
ルからインポート可能でなければなりません。

注釈:

  pickle プロトコルバージョン 4 では他のクラスで入れ子になった列挙型の
  pickle 化も容易です。

Enum メンバーをどう pickle 化/unpickle 化するかは、列挙型クラス内の
"__reduce_ex__()" で定義することで変更できます。


機能 API
========

"Enum" クラスは呼び出し可能で、以下の機能 API を提供しています:

   >>> Animal = Enum('Animal', 'ANT BEE CAT DOG')
   >>> Animal
   <enum 'Animal'>
   >>> Animal.ANT
   <Animal.ANT: 1>
   >>> Animal.ANT.value
   1
   >>> list(Animal)
   [<Animal.ANT: 1>, <Animal.BEE: 2>, <Animal.CAT: 3>, <Animal.DOG: 4>]

この API の動作は "namedtuple" と似ています。"Enum" 呼び出しの第 1 引
数は列挙型の名前です。

第 2 引数は列挙型メンバー名の *ソース* です。空白で区切った名前の文字
列、名前のシーケンス、キー/値のペアの 2 要素タプルのシーケンス、あるい
は名前と値のマッピング (例: 辞書) を指定できます。最後の 2 個のオプシ
ョンでは、列挙型へ任意の値を割り当てることができます。前の 2 つのオプ
ションでは、1 から始まり増加していく整数を自動的に割り当てます (別の開
始値を指定するには、"start" 引数を使用します)。"Enum" から派生した新し
いクラスが返されます。言い換えれば、上記の "Animal" への割り当ては以下
と等価です:

   >>> class Animal(Enum):
   ...     ANT = 1
   ...     BEE = 2
   ...     CAT = 3
   ...     DOG = 4
   ...

デフォルトの開始番号が "0" ではなく "1" である理由は、"0" がブール演算
子では "False" になりますが、すべての列挙型メンバーの評価は "True" で
なければならないためです。

機能 API による Enum の pickle 化は、その列挙型がどのモジュールで作成
されたかを見つけ出すためにフレームスタックの実装の詳細が使われるので、
トリッキーになることがあります (例えば別のモジュールのユーティリティ関
数を使うと失敗しますし、IronPython や Jython ではうまくいきません)。解
決策は、以下のようにモジュール名を明示的に指定することです:

   >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', module=__name__)

警告:

  "module" が与えられない場合、Enum はそれがなにか決定できないため、新
  しい Enum メンバーは unpickle 化できなくなります; エラーをソースの近
  いところで発生させるため、pickle 化は無効になります。

新しい pickle プロトコルバージョン 4 では、一部の状況において、pickle
がクラスを発見するための場所の設定に "__qualname__" を参照します。例え
ば、そのクラスがグローバルスコープ内のクラス SomeData 内で利用可能とす
るには以下のように指定します:

   >>> Animal = Enum('Animal', 'ANT BEE CAT DOG', qualname='SomeData.Animal')

完全な構文は以下のようになります:

   Enum(value='NewEnumName', names=<...>, *, module='...', qualname='...', type=<mixed-in class>, start=1)

value:
   新しい Enum クラスに記録されるそれ自身の名前です。

名前:
   Enum のメンバーです。 空白またはカンマで区切った文字列でも構いませ
   ん (特に指定がない限り、値は 1 から始まります):

      'RED GREEN BLUE' | 'RED,GREEN,BLUE' | 'RED, GREEN, BLUE'

   または名前のイテレータで指定もできます:

      ['RED', 'GREEN', 'BLUE']

   または (名前, 値) のペアのイテレータでも指定できます:

      [('CYAN', 4), ('MAGENTA', 5), ('YELLOW', 6)]

   またはマッピングでも指定できます:

      {'CHARTREUSE': 7, 'SEA_GREEN': 11, 'ROSEMARY': 42}

module:
   新しい Enum クラスが属するモジュールの名前です。

qualname:
   新しい Enum クラスが属するモジュールの場所です。

type:
   新しい Enum クラスに複合されるデータ型です。

start:
   names のみが渡されたときにカウントを開始する数です。

バージョン 3.5 で変更: *start* 引数が追加されました。


派生列挙型
==========


IntEnum
-------

提供されている 1 つ目の "Enum" の派生型であり、 "int" のサブクラスでも
あります。 "IntEnum" のメンバーは整数と比較できます; さらに言うと、異
なる整数列挙型どうしでも比較できます:

   >>> from enum import IntEnum
   >>> class Shape(IntEnum):
   ...     CIRCLE = 1
   ...     SQUARE = 2
   ...
   >>> class Request(IntEnum):
   ...     POST = 1
   ...     GET = 2
   ...
   >>> Shape == 1
   False
   >>> Shape.CIRCLE == 1
   True
   >>> Shape.CIRCLE == Request.POST
   True

ただし、これらも標準の "Enum" 列挙型とは比較できません:

   >>> class Shape(IntEnum):
   ...     CIRCLE = 1
   ...     SQUARE = 2
   ...
   >>> class Color(Enum):
   ...     RED = 1
   ...     GREEN = 2
   ...
   >>> Shape.CIRCLE == Color.RED
   False

"IntEnum" の値は他の用途では整数のように振る舞います:

   >>> int(Shape.CIRCLE)
   1
   >>> ['a', 'b', 'c'][Shape.CIRCLE]
   'b'
   >>> [i for i in range(Shape.SQUARE)]
   [0, 1]


IntFlag
-------

提供されている 2 つ目の "Enum" の派生型 "IntFlag" も "int" を基底クラ
スとしています。 "IntFlag" メンバーが  "Enum" メンバーと異なるのは、ビ
ット演算子 (&, |, ^, ~) を使って組み合わせられ、その結果も "IntFlag"
メンバーになることです。 しかし、名前が示すように、 "IntFlag" は "int"
のサブクラスでもあり、 "int" が使われるところでもどこでも使えます。
"IntFlag" メンバーに対してビット演算以外のどんな演算をしても、その結果
は "IntFlag" メンバーではなくなります。

バージョン 3.6 で追加.

"IntFlag" クラスの例:

   >>> from enum import IntFlag
   >>> class Perm(IntFlag):
   ...     R = 4
   ...     W = 2
   ...     X = 1
   ...
   >>> Perm.R | Perm.W
   <Perm.R|W: 6>
   >>> Perm.R + Perm.W
   6
   >>> RW = Perm.R | Perm.W
   >>> Perm.R in RW
   True

組み合わせにも名前を付けられます:

   >>> class Perm(IntFlag):
   ...     R = 4
   ...     W = 2
   ...     X = 1
   ...     RWX = 7
   >>> Perm.RWX
   <Perm.RWX: 7>
   >>> ~Perm.RWX
   <Perm.-8: -8>

"IntFlag" と "Enum" のもう 1 つの重要な違いは、フラグが設定されていな
い (値が0である) 場合、その真偽値としての評価は "False" になることです
:

   >>> Perm.R & Perm.X
   <Perm.0: 0>
   >>> bool(Perm.R & Perm.X)
   False

"IntFlag" は "int" のサブクラスでもあるので、その両者を組み合わせられ
ます:

   >>> Perm.X | 8
   <Perm.8|X: 9>


Flag
----

最後の派生型は "Flag" です。 "IntFlag" と同様に、 "Flag" メンバーもビ
ット演算子 (&, |, ^, ~) を使って組み合わせられます。 しかし "IntFlag"
とは違い、他のどの "Flag" 列挙型とも "int" とも組み合わせたり、比較し
たりできません。 値を直接指定することも可能ですが、値として "auto" を
使い、 "Flag" に適切な値を選ばせることが推奨されています。

バージョン 3.6 で追加.

"IntFlag" と同様に、 "Flag" メンバーの組み合わせがどのフラグも設定され
ていない状態になった場合、その真偽値としての評価は "False" となります:

   >>> from enum import Flag, auto
   >>> class Color(Flag):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> Color.RED & Color.GREEN
   <Color.0: 0>
   >>> bool(Color.RED & Color.GREEN)
   False

個別のフラグは 2 のべき乗 (1, 2, 4, 8, ...) の値を持つべきですが、フラ
グの組み合わせはそうはなりません:

   >>> class Color(Flag):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...     WHITE = RED | BLUE | GREEN
   ...
   >>> Color.WHITE
   <Color.WHITE: 7>

"フラグが設定されていない" 状態に名前を付けても、その真偽値は変わりま
せん:

   >>> class Color(Flag):
   ...     BLACK = 0
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> Color.BLACK
   <Color.BLACK: 0>
   >>> bool(Color.BLACK)
   False

注釈:

  ほとんどの新しいコードでは、 "Enum" と "Flag" が強く推奨されます。
  というのは、 "IntEnum" と "IntFlag" は (整数と比較でき、従って推移的
  に他の無関係な列挙型と比較できてしまうことにより) 列挙型の意味論的な
  約束に反するからです。 "IntEnum" と "IntFlag" は、 "Enum" や "Flag"
  では上手くいかない場合のみに使うべきです; 例えば、整数定数を列挙型で
  置き換えるときや、他のシステムとの相互運用性を持たせたいときです。


その他
------

"IntEnum" は "enum" モジュールの一部ですが、単独での実装もとても簡単に
行なえます:

   class IntEnum(int, Enum):
       pass

ここでは似たような列挙型の派生を定義する方法を紹介します; 例えば、
"StrEnum" は "int" ではなく "str" で複合させたものです。

いくつかのルール:

1. "Enum" のサブクラスを作成するとき、複合させるデータ型は、基底クラス
   の並びで "Enum" 自身より先に記述しなければなりません (上記
   "IntEnum" の例を参照)。

2. "Enum" のメンバーはどんなデータ型でも構いませんが、追加のデータ型 (
   例えば、上の例の "int") と複合させてしまうと、すべてのメンバーの値
   はそのデータ型でなければならなくなります。 この制限は、メソッドの追
   加するだけの、 "int" や "str" のような他のデータ型を指定しない複合
   には適用されません。

3. 他のデータ型と複合された場合、 "value" 属性は、たとえ等価であり等価
   であると比較が行えても、列挙型メンバー自身としては *同じではありま
   せん* 。

4. %-方式の書式:  *%s* および *%r* はそれぞれ "Enum" クラスの
   "__str__()" および "__repr__()" を呼び出します; その他のコード
   (IntEnum の *%i* や *%h* など) は列挙型のメンバーを複合されたデータ
   型として扱います。

5. フォーマット済み文字列リテラル 、 "str.format()" 、 "format()" は、
   "__str__()" やサブクラスでオーバーライドされた "__format__()" より
   もミックスイン型の "__format__()" を優先して使います。!sや!rフォー
   マットコードを使うと、 "Enum" クラスの "__str__()" や "__repr__()"
   メソッドが強制的に使われます。


"__init__()"  と "__init__()" のどちらを使うべきか
==================================================

"__new__()" は "Enum" メンバーの実際の値をカスタマイズしたいときに利用
します。他の変更を加える場合、 "__new__()" と "__init__()" のどちらを
利用するかは、"__init__()" の方が望ましいでしょう。

例えば、複数の値をコンストラクタに渡すが、その中の1つだけを値として使
いたい場合は次のようにします:

   >>> class Coordinate(bytes, Enum):
   ...     """
   ...     Coordinate with binary codes that can be indexed by the int code.
   ...     """
   ...     def __new__(cls, value, label, unit):
   ...         obj = bytes.__new__(cls, [value])
   ...         obj._value_ = value
   ...         obj.label = label
   ...         obj.unit = unit
   ...         return obj
   ...     PX = (0, 'P.X', 'km')
   ...     PY = (1, 'P.Y', 'km')
   ...     VX = (2, 'V.X', 'km/s')
   ...     VY = (3, 'V.Y', 'km/s')
   ...

   >>> print(Coordinate['PY'])
   Coordinate.PY

   >>> print(Coordinate(3))
   Coordinate.VY


興味深い例
==========

"Enum", "IntEnum", "IntFlag", "Flag" は用途の大部分をカバーすると予想
されますが、そのすべてをカバーできているわけではありません。 ここでは
、そのまま、あるいは独自の列挙型を作る例として使える、様々なタイプの列
挙型を紹介します。


値の省略
--------

多くの用途では、列挙型の実際の値が何かは気にされません。 このタイプの
単純な列挙型を定義する方法はいくつかあります:

* 値に "auto" インスタンスを使用する

* 値として "object" インスタンスを使用する

* 値として解説文字列を使用する

* 値としてタプルを使用し、独自の "__new__()" を使用してタプルを "int"
  値で置き換える

これらのどの方法を使ってもユーザーに対して、値は重要ではなく、他のメン
バーの番号の振り直しをする必要無しに、メンバーの追加、削除、並べ替えが
行えるということを示せます。

どの方法を選んでも、(重要でない) 値を隠す "repr()" を提供すべきです:

   >>> class NoValue(Enum):
   ...     def __repr__(self):
   ...         return '<%s.%s>' % (self.__class__.__name__, self.name)
   ...


"auto" を使う
~~~~~~~~~~~~~

"auto" を使うと次のようになります:

   >>> class Color(NoValue):
   ...     RED = auto()
   ...     BLUE = auto()
   ...     GREEN = auto()
   ...
   >>> Color.GREEN
   <Color.GREEN>


"object" を使う
~~~~~~~~~~~~~~~

"object" を使うと次のようになります:

   >>> class Color(NoValue):
   ...     RED = object()
   ...     GREEN = object()
   ...     BLUE = object()
   ...
   >>> Color.GREEN
   <Color.GREEN>


解説文字列を使う
~~~~~~~~~~~~~~~~

値として文字列を使うと次のようになります:

   >>> class Color(NoValue):
   ...     RED = 'stop'
   ...     GREEN = 'go'
   ...     BLUE = 'too fast!'
   ...
   >>> Color.GREEN
   <Color.GREEN>
   >>> Color.GREEN.value
   'go'


独自の "__new__()" を使う
~~~~~~~~~~~~~~~~~~~~~~~~~

自動で番号を振る "__new__()" を使うと次のようになります:

   >>> class AutoNumber(NoValue):
   ...     def __new__(cls):
   ...         value = len(cls.__members__) + 1
   ...         obj = object.__new__(cls)
   ...         obj._value_ = value
   ...         return obj
   ...
   >>> class Color(AutoNumber):
   ...     RED = ()
   ...     GREEN = ()
   ...     BLUE = ()
   ...
   >>> Color.GREEN
   <Color.GREEN>
   >>> Color.GREEN.value
   2

"AutoNumber" をより広い用途で使うには、シグニチャに "*args" を追加しま
す:

   >>> class AutoNumber(NoValue):
   ...     def __new__(cls, *args):      # this is the only change from above
   ...         value = len(cls.__members__) + 1
   ...         obj = object.__new__(cls)
   ...         obj._value_ = value
   ...         return obj
   ...

"AutoNumber" を継承すると、追加の引数を取り扱える独自の "__init__" が
書けます。

   >>> class Swatch(AutoNumber):
   ...     def __init__(self, pantone='unknown'):
   ...         self.pantone = pantone
   ...     AUBURN = '3497'
   ...     SEA_GREEN = '1246'
   ...     BLEACHED_CORAL = () # New color, no Pantone code yet!
   ...
   >>> Swatch.SEA_GREEN
   <Swatch.SEA_GREEN: 2>
   >>> Swatch.SEA_GREEN.pantone
   '1246'
   >>> Swatch.BLEACHED_CORAL.pantone
   'unknown'

注釈:

  "__new__()" メソッドが定義されていれば、Enum 番号の作成時に使用され
  ます; これは Enum の "__new__()" と置き換えられ、クラスが作成された
  後の既存の番号を取得に使用されます。


OrderedEnum
-----------

"IntEnum" をベースとしないため、通常の "Enum" の不変条件 (他の列挙型と
比較できないなど) のままで、メンバーを順序付けできる列挙型です:

   >>> class OrderedEnum(Enum):
   ...     def __ge__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value >= other.value
   ...         return NotImplemented
   ...     def __gt__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value > other.value
   ...         return NotImplemented
   ...     def __le__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value <= other.value
   ...         return NotImplemented
   ...     def __lt__(self, other):
   ...         if self.__class__ is other.__class__:
   ...             return self.value < other.value
   ...         return NotImplemented
   ...
   >>> class Grade(OrderedEnum):
   ...     A = 5
   ...     B = 4
   ...     C = 3
   ...     D = 2
   ...     F = 1
   ...
   >>> Grade.C < Grade.A
   True


DuplicateFreeEnum
-----------------

値が同じメンバーが見つかった場合、別名を作るのではなく、エラーを送出し
ます:

   >>> class DuplicateFreeEnum(Enum):
   ...     def __init__(self, *args):
   ...         cls = self.__class__
   ...         if any(self.value == e.value for e in cls):
   ...             a = self.name
   ...             e = cls(self.value).name
   ...             raise ValueError(
   ...                 "aliases not allowed in DuplicateFreeEnum:  %r --> %r"
   ...                 % (a, e))
   ...
   >>> class Color(DuplicateFreeEnum):
   ...     RED = 1
   ...     GREEN = 2
   ...     BLUE = 3
   ...     GRENE = 2
   ...
   Traceback (most recent call last):
   ...
   ValueError: aliases not allowed in DuplicateFreeEnum:  'GRENE' --> 'GREEN'

注釈:

  これは Enum に別名を無効にするのと同様な振る舞いの追加や変更をおこな
  うためのサブクラス化に役立つ例です。単に別名を無効にしたいだけなら、
  "unique()" デコレーターを使用して行えます。


Planet
------

"__new__()" や "__init__()" が定義されている場合、列挙型メンバーの値は
これらのメソッドに渡されます:

   >>> class Planet(Enum):
   ...     MERCURY = (3.303e+23, 2.4397e6)
   ...     VENUS   = (4.869e+24, 6.0518e6)
   ...     EARTH   = (5.976e+24, 6.37814e6)
   ...     MARS    = (6.421e+23, 3.3972e6)
   ...     JUPITER = (1.9e+27,   7.1492e7)
   ...     SATURN  = (5.688e+26, 6.0268e7)
   ...     URANUS  = (8.686e+25, 2.5559e7)
   ...     NEPTUNE = (1.024e+26, 2.4746e7)
   ...     def __init__(self, mass, radius):
   ...         self.mass = mass       # in kilograms
   ...         self.radius = radius   # in meters
   ...     @property
   ...     def surface_gravity(self):
   ...         # universal gravitational constant  (m3 kg-1 s-2)
   ...         G = 6.67300E-11
   ...         return G * self.mass / (self.radius * self.radius)
   ...
   >>> Planet.EARTH.value
   (5.976e+24, 6378140.0)
   >>> Planet.EARTH.surface_gravity
   9.802652743337129


TimePeriod
----------

"_ignore_" 属性の使用方法のサンプルです:

   >>> from datetime import timedelta
   >>> class Period(timedelta, Enum):
   ...     "different lengths of time"
   ...     _ignore_ = 'Period i'
   ...     Period = vars()
   ...     for i in range(367):
   ...         Period['day_%d' % i] = i
   ...
   >>> list(Period)[:2]
   [<Period.day_0: datetime.timedelta(0)>, <Period.day_1: datetime.timedelta(days=1)>]
   >>> list(Period)[-2:]
   [<Period.day_365: datetime.timedelta(days=365)>, <Period.day_366: datetime.timedelta(days=366)>]


Enum はどう違うのか?
====================

Enum は Enum 派生クラスやそれらのインスタンス (メンバー) 双方の多くの
側面に影響を及ぼすカスタムメタクラスを持っています。


Enum クラス
-----------

"EnumMeta" メタクラスは、"__contains__()"、"__dir__()"、"__iter__()"
および標準的なクラスでは失敗するが "Enum" クラスでは動作するその他のメ
ソッド (*list(Color)* や *some_enum_var in Color* など) を責任を持って
提供します。"EnumMeta" は最終的な "Enum" クラスのさまざまなメソッド
("__new__()"、"__getnewargs__()"、"__str__()" および "__repr__()") が
正しいことを責任を持って保証します。


Enum メンバー (インスタンス)
----------------------------

Enum メンバーについて最も興味深いのは、それらがシングルトンであるとい
うことです。"EnumMeta" は "Enum" 自身を作成し、メンバーを作成し、新し
いインスタンスが作成されていないかどうかを確認するために既存のメンバー
インスタンスだけを返すカスタム "__new__()" を追加します。


細かい点
--------


"__dunder__" 名のサポート
~~~~~~~~~~~~~~~~~~~~~~~~~

"__members__" は読み込み専用の、 "member_name":"member"  を要素とする
順序付きマッピングです。これはクラスでのみ利用可能です。

"__new__()" が、もし指定されていた場合、列挙型のメンバーを作成し、返し
ます; そのメンバー の "_value_" を適切に設定するのも非常によい考えです
。 いったん全てのメンバーが作成されると、それ以降 "__new__()" は使われ
ません。


"_sunder_" 名のサポート
~~~~~~~~~~~~~~~~~~~~~~~

* "_name_" -- メンバー名

* "_value_" -- メンバーの値; "__new__" で設定したり、変更したりできま
  す

* "_missing_" -- 値が見付からなかったときに使われる検索関数; オーバー
  ライドされていることがあります

* "_ignore_" -- a list of names, either as a "list()" or a "str()",
  that will not be transformed into members, and will be removed from
  the final class

* "_order_" -- Python 2/3のコードでメンバーの順序を固定化するのに利用
  されます（クラス属性で、クラス作成時に削除されます）

* "_generate_next_value_" -- Functional API から利用され、 "auto" が列
  挙型のメンバーの適切な値を取得するのに使われます。オーバーライドされ
  ます。

バージョン 3.6 で追加: "_missing_", "_order_", "_generate_next_value_"

バージョン 3.7 で追加: "_ignore_"

Pythono 2 / Python 3のコードの同期を取りやすくするために "_order_" 属
性を提供できます。実際の列挙値の順序と比較して一致してなければエラーを
送出します:

   >>> class Color(Enum):
   ...     _order_ = 'RED GREEN BLUE'
   ...     RED = 1
   ...     BLUE = 3
   ...     GREEN = 2
   ...
   Traceback (most recent call last):
   ...
   TypeError: member order does not match _order_

注釈:

  Python 2のコードでは "_order_" 属性は定義順が記録される前消えてしま
  うため、重要です。


"Enum" メンバー型
~~~~~~~~~~~~~~~~~

"Enum" メンバーは、それらの "Enum" クラスのインスタンスで、通常は
"EnumClass.member" のようにアクセスします。 ある状況下では、
"EnumClass.member.member" としてもアクセスできますが、この方法は絶対に
使うべきではありません。 というのは、この検索は失敗するか、さらに悪い
場合には、探している "Enum" メンバー以外のものを返す場合もあるからです
(これがメンバーの名前に大文字のみを使うのが良い理由の 1 つでもあります
):

   >>> class FieldTypes(Enum):
   ...     name = 0
   ...     value = 1
   ...     size = 2
   ...
   >>> FieldTypes.value.size
   <FieldTypes.size: 2>
   >>> FieldTypes.size.value
   2

バージョン 3.5 で変更.


"Enum" クラスとメンバーの真偽値
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

("int", "str" などのような) 非 "Enum" 型と複合させた "Enum" のメンバー
は、その複合された型の規則に従って評価されます; そうでない場合は、全て
のメンバーは "True" と評価されます。 メンバーの値に依存する独自の Enum
の真偽値評価を行うには、クラスに次のコードを追加してください:

   def __bool__(self):
       return bool(self.value)

"Enum" クラスは常に "True" と評価されます。


メソッド付きの "Enum" クラス
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

"Enum" サブクラスに追加のメソッドを与えた場合、上述の Planet クラスの
ように、そのメソッドはメンバーの "dir()" に表示されますが、クラスの
"dir()" には表示されません:

   >>> dir(Planet)
   ['EARTH', 'JUPITER', 'MARS', 'MERCURY', 'NEPTUNE', 'SATURN', 'URANUS', 'VENUS', '__class__', '__doc__', '__members__', '__module__']
   >>> dir(Planet.EARTH)
   ['__class__', '__doc__', '__module__', 'name', 'surface_gravity', 'value']


"Flag" のメンバーの組み合わせ
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Flag メンバーの組み合わせに名前が無い場合、 "repr()" の出力には、その
値にある全ての名前を持つフラグと全ての名前を持つ組み合わせが含まれます
:

   >>> class Color(Flag):
   ...     RED = auto()
   ...     GREEN = auto()
   ...     BLUE = auto()
   ...     MAGENTA = RED | BLUE
   ...     YELLOW = RED | GREEN
   ...     CYAN = GREEN | BLUE
   ...
   >>> Color(3)  # named combination
   <Color.YELLOW: 3>
   >>> Color(7)      # not named combination
   <Color.CYAN|MAGENTA|BLUE|YELLOW|GREEN|RED: 7>
