enum —列挙型のサポート—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.9/library/enum
移動先:案内検索

enum —列挙型のサポート

バージョン3.4の新機能。


ソースコード: :source: `Lib / enum.py`



列挙型は、一意の定数値にバインドされたシンボリック名(メンバー)のセットです。 列挙内では、メンバーをIDで比較したり、列挙自体を繰り返し実行したりできます。

ノート

列挙型メンバーの場合

列挙型は定数を表すために使用されるため、列挙型メンバーにはUPPER_CASE名を使用することをお勧めします。この例では、そのスタイルを使用します。


モジュールの内容

このモジュールは、名前と値の一意のセットを定義するために使用できる4つの列挙クラスを定義します: EnumIntEnumFlag 、および IntFlag [X168X ]。 また、1つのデコレータ unique()と1つのヘルパー auto も定義します。

class enum.Enum
列挙型定数を作成するための基本クラス。 別の構築構文については、セクション機能API を参照してください。
class enum.IntEnum
int のサブクラスでもある列挙型定数を作成するための基本クラス。
class enum.IntFlag
IntFlag メンバーシップを失うことなく、ビット演算子を使用して組み合わせることができる列挙型定数を作成するための基本クラス。 IntFlag メンバーは、 int のサブクラスでもあります。
class enum.Flag
Flag メンバーシップを失うことなく、ビット演算を使用して組み合わせることができる列挙型定数を作成するための基本クラス。
enum.unique()
1つの名前のみが任意の1つの値にバインドされることを保証する列挙型クラスデコレータ。
class enum.auto
インスタンスは、列挙型メンバーの適切な値に置き換えられます。 デフォルトでは、初期値は1から始まります。

バージョン3.6の新機能: FlagIntFlagauto


列挙型の作成

列挙型は class 構文を使用して作成されるため、読み取りと書き込みが簡単です。 別の作成方法については、 Functional API で説明されています。 列挙型を定義するには、 Enum を次のようにサブクラス化します。

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

ノート

列挙型メンバー値

メンバー値は、 intstr などの任意の値にすることができます。 正確な値が重要でない場合は、 auto インスタンスを使用でき、適切な値が選択されます。 auto を他の値と混合する場合は、注意が必要です。


ノート

命名法

  • クラスColorは、列挙型(または列挙型)です。
  • 属性Color.REDColor.GREENなどは、列挙型メンバー(または列挙型メンバー)であり、機能的に定数です。
  • 列挙型メンバーには名前があります(Color.REDの名前はREDColor.BLUEの値は3など)


ノート

class 構文を使用して列挙型を作成しますが、列挙型は通常のPythonクラスではありません。 詳細については、列挙型の違いは何ですか?を参照してください。


列挙型メンバーには、人間が読める形式の文字列表現があります。

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

…彼らのreprにはより多くの情報があります:

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

列挙型メンバーの type は、それが属する列挙型です。

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

列挙型メンバーには、アイテム名だけを含むプロパティもあります。

>>> 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>

name で列挙型メンバーにアクセスする場合は、アイテムアクセスを使用します。

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

列挙型メンバーがあり、そのnameまたはvalueが必要な場合:

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

列挙型メンバーと値の複製

同じ名前の2つの列挙型メンバーを持つことは無効です:

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

ただし、2つの列挙型メンバーは同じ値を持つことができます。 同じ値を持つ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>

ノート

すでに定義されている属性(別のメンバー、メソッドなど)と同じ名前のメンバーを作成しようとしたり、メンバーと同じ名前の属性を作成しようとしたりすることはできません。


一意の列挙値を確保する

デフォルトでは、列挙は同じ値のエイリアスとして複数の名前を許可します。 この動作が望ましくない場合は、次のデコレータを使用して、各値が列挙で1回だけ使用されるようにすることができます。

@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']

比較

列挙型メンバーはIDによって比較されます。

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

列挙値間の順序付き比較はサポートされていません。 列挙型メンバーは整数ではありません(ただし、以下の 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

許可されたメンバーと列挙の属性

上記の例では、列挙値に整数を使用しています。 整数の使用は短くて便利ですが( Functional 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'

許可されるルールは次のとおりです。単一のアンダースコアで開始および終了する名前は列挙型によって予約されており、使用できません。 列挙内で定義された他のすべての属性は、特別なメソッド(__str__()__add__()など)、記述子(メソッドも記述子)、および変数名を除いて、この列挙のメンバーになります。 _ignore_にリストされています。

注:列挙型で__new__()または__init__()、あるいはその両方が定義されている場合、列挙型メンバーに指定された値はすべてこれらのメソッドに渡されます。 例については、 Planet を参照してください。


制限付き列挙型サブクラス化

新しい Enum クラスには、1つの基本Enumクラス、最大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 を参照してください。)


酸洗い

列挙は、ピクル化およびピクルス解除できます。

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

ピクルス化の通常の制限が適用されます。ピクルス化解除ではモジュールからインポート可能である必要があるため、ピクルス可能な列挙型はモジュールのトップレベルで定義する必要があります。

ノート

pickleプロトコルバージョン4を使用すると、他のクラスにネストされた列挙型を簡単にpickle化できます。


列挙型クラスで__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 の呼び出しの最初の引数は、列挙の名前です。

2番目の引数は、列挙メンバー名の source です。 これは、空白で区切られた名前の文字列、名前のシーケンス、キーと値のペアを持つ2つのタプルのシーケンス、またはマッピング(例: 辞書)名前から値へ。 最後の2つのオプションを使用すると、列挙に任意の値を割り当てることができます。 その他は、1から始まる増加する整数を自動割り当てします(startパラメーターを使用して別の開始値を指定します)。 Enum から派生した新しいクラスが返されます。 つまり、上記のAnimalへの割り当ては次のようになります。

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

0ではなく1を開始番号としてデフォルト設定する理由は、0がブール値の意味でFalseであるためですが、列挙型メンバーはすべて[ X164X] 。

機能APIで作成された列挙型のピクルス化は、フレームスタックの実装の詳細を使用して、列挙型が作成されているモジュールを特定しようとするため、注意が必要な場合があります(例: 別のモジュールでユーティリティ関数を使用すると失敗し、IronPythonまたはJythonでも機能しない可能性があります)。 解決策は、次のようにモジュール名を明示的に指定することです。

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

警告

moduleが指定されておらず、Enumがそれが何であるかを判別できない場合、新しいEnumメンバーは選択できなくなりません。 エラーをソースに近づけるために、pickle化は無効になります。


新しいピクルスプロトコル4も、状況によっては、 __ qualname __ がピクルスがクラスを見つけることができる場所に設定されていることに依存しています。 たとえば、クラスがグローバルスコープのSomeDataクラスで使用可能になった場合:

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

完全な署名は次のとおりです。

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

新しい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}
モジュール

新しいEnumクラスを見つけることができるモジュールの名前。

qualname

モジュール内の新しいEnumクラスが見つかります。

タイプ

新しいEnumクラスにミックスインするタイプ。

始める

名前のみが渡された場合にカウントを開始する番号。

バージョン3.5で変更: start パラメーターが追加されました。


派生列挙

IntEnum

提供される 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

提供される Enum の次のバリエーションである IntFlag も、 int に基づいています。 違いは IntFlag メンバーはビット演算子(&、|、^、〜)を使用して組み合わせることができ、結果は引き続き 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>

IntFlagEnum のもう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 です。 お気に入り IntFlag国旗メンバーは、ビット演算子(&、|、^、〜)を使用して組み合わせることができます。 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

ノート

IntEnumIntFlag は列挙型のセマンティックな約束を破るため、新しいコードの大部分では、 EnumFlag を強くお勧めします(整数に匹敵することによって、したがって他の無関係な列挙への推移性によって)。 IntEnum および IntFlag は、 Enum および Flag が機能しない場合にのみ使用する必要があります。 たとえば、整数定数が列挙型に置き換えられた場合、または他のシステムとの相互運用性のために。


その他

IntEnumenum モジュールの一部ですが、独立して実装するのは非常に簡単です。

class IntEnum(int, Enum):
    pass

これは、同様の派生列挙を定義する方法を示しています。 たとえば、 int の代わりに str を混合するStrEnum

いくつかのルール:

  1. Enum をサブクラス化する場合、上記の IntEnum の例のように、ミックスインタイプは Enum 自体の前に塩基のシーケンスで表示される必要があります。
  2. Enum には任意のタイプのメンバーを含めることができますが、追加のタイプを混在させると、すべてのメンバーにそのタイプの値が必要になります。 上記の int 。 この制限は、メソッドを追加するだけで別のタイプを指定しないミックスインには適用されません。
  3. 別のデータ型が混在している場合、value属性は列挙型メンバー自体と同じではありませんが、同等であり、同等に比較されます。
  4. %スタイルのフォーマット:%s および%r は、それぞれ Enum クラスの__str__()および__repr__()を呼び出します。 他のコード(IntEnumの%i や%h など)は、列挙型メンバーを混合型として扱います。
  5. フォーマットされた文字列リテラルstr.format()、および format()は、 [でない限り、混合型の__format__()を使用します。 X131X]または__format__()はサブクラスでオーバーライドされます。この場合、オーバーライドされたメソッドまたは Enum メソッドが使用されます。 !sおよび!rフォーマットコードを使用して、 Enum クラスの__str__()および__repr__()メソッドの使用を強制します。


__new__()を使用する場合と __init__()

Enum メンバーの実際の値をカスタマイズする場合は、__new__()を使用する必要があります。 その他の変更は、__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

興味深い例

EnumIntEnumIntFlag 、および Flag は、ユースケースの大部分をカバーすることが期待されていますが、すべてをカバーすることはできません。 これは、直接使用できる、または独自の列挙を作成するための例として使用できる、いくつかの異なるタイプの列挙のレシピです。

値を省略する

多くのユースケースでは、列挙型の実際の値が何であるかは気にしません。 このタイプの単純な列挙を定義するには、いくつかの方法があります。

  • 値に auto のインスタンスを使用します
  • オブジェクトのインスタンスを値として使用します
  • 値として説明文字列を使用する
  • タプルを値として使用し、カスタム__new__()を使用して、タプルを int 値に置き換えます。

これらの方法のいずれかを使用すると、これらの値は重要ではないことをユーザーに示し、残りのメンバーの番号を付け直すことなく、メンバーを追加、削除、または並べ替えることができます。

どちらの方法を選択する場合でも、(重要でない)値も非表示にする repr()を提供する必要があります。

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

自動の使用

auto を使用すると、次のようになります。

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

オブジェクトを使用する

オブジェクトを使用すると、次のようになります。

>>> 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の__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'

ノート

これは、列挙型をサブクラス化して他の動作を追加または変更したり、エイリアスを禁止したりする場合に便利な例です。 必要な変更がエイリアスの禁止のみである場合は、代わりに unique()デコレータを使用できます。


__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)>]

列挙型はどのように異なりますか?

列挙型には、派生した列挙型クラスとそのインスタンス(メンバー)の両方の多くの側面に影響を与えるカスタムメタクラスがあります。

列挙型クラス

EnumMetaメタクラスは、__contains__()__dir__()__iter__()、および列挙型[X151X ] Color の list(Color)や some_enum_varなど、一般的なクラスで失敗するクラス。 EnumMetaは、最後の Enum クラスの他のさまざまなメソッド(__new__()__getnewargs__()__str__()など)が正しいことを確認する責任があります。および__repr__())。


列挙型メンバー(別名インスタンス)

列挙型メンバーの最も興味深い点は、それらがシングルトンであるということです。 EnumMetaは、 Enum クラス自体を作成している間にそれらをすべて作成し、カスタム__new__()を配置して、新しいものがインスタンス化されないようにします。既存のメンバーインスタンス。


より細かいポイント

サポートされている__dunder__名

__members__は、member_namememberアイテムの読み取り専用の順序付きマッピングです。 クラスでのみご利用いただけます。

__new__()は、指定されている場合、列挙型メンバーを作成して返す必要があります。 メンバーの_value_を適切に設定することも非常に良い考えです。 すべてのメンバーが作成されると、それは使用されなくなります。


サポートされている_sunder_名

  • _name_ –メンバーの名前
  • _value_ –メンバーの値。 __new__で設定/変更できます
  • _missing_ –値が見つからない場合に使用されるルックアップ関数。 上書きされる可能性があります
  • _ignore_list または str としての名前のリストで、メンバーに変換されず、最終クラスから削除されます
  • _order_ –メンバーの順序が一貫していることを確認するためにPython 2/3コードで使用されます(クラス属性、クラス作成中に削除されます)
  • _generate_next_value_Functional API および auto によって使用され、列挙型メンバーの適切な値を取得します。 上書きされる可能性があります

バージョン3.6の新機能: _missing__order__generate_next_value_


バージョン3.7の新機能: _ignore_


Python 2 / Python 3コードの同期を維持するために、_order_属性を指定できます。 列挙の実際の順序と照合され、2つが一致しない場合はエラーが発生します。

>>> 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_属性が必要です。これは、定義の順序が記録される前に失われるためです。


_Private__names

プライベート名は、エラーやメンバーではなく、Python 3.10の通常の属性になります(名前がアンダースコアで終わるかどうかによって異なります)。 3.9でこれらの名前を使用すると、 DeprecationWarning が発行されます。


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クラスとメンバーのブール値

Enum 以外のタイプ( intstr など)と混合された Enum メンバーは、混合に従って評価されます。 -タイプのルールで; それ以外の場合、すべてのメンバーは True と評価されます。 独自の列挙型のブール評価をメンバーの値に依存させるには、クラスに以下を追加します。

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

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


Enumクラスとメソッド

上記の Planet クラスのように、 Enum サブクラスに追加のメソッドを指定すると、それらのメソッドはメンバーの 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>