enum
--- 列挙型のサポート¶
バージョン 3.4 で追加.
ソースコード: Lib/enum.py
列挙型は、一意の定数値に束縛された識別名 (メンバー) の集合です。列挙型の中でメンバーの同一性を比較でき、列挙型自身でイテレートが可能です。
注釈
Case of Enum Members
Because Enums are used to represent constants we recommend using UPPER_CASE names for enum members, and will be using that style in our examples.
モジュールコンテンツ¶
このモジュールでは一意の名前と値の集合を定義するのに使用できる 4 つの列挙型クラス Enum
, IntEnum
, Flag
, IntFlag
を定義しています。
このモジュールはデコレータの unique()
とヘルパークラスの auto
も定義しています。
-
class
enum.
IntFlag
¶ 列挙型定数を作成する基底クラスで、ビット演算子を使って組み合わせられ、その結果も
IntFlag
メンバーになります。IntFlag
はint
のサブクラスでもあります。
-
enum.
unique
() 一つの名前だけがひとつの値に束縛されていることを保証する Enum クラスのデコレーターです。
-
class
enum.
auto
¶ Instances are replaced with an appropriate value for Enum members. By default, the initial value starts at 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'>]
注釈
The goal of the default _generate_next_value_()
method is to provide
the next int
in sequence with the last int
provided, but
the way it does this is an implementation detail and may change.
注釈
The _generate_next_value_()
method must be defined before any members.
イテレーション¶
列挙型のメンバーのイテレートは別名をサポートしていません:
>>> 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'
The rules for what is allowed are as follows: names that start and end with
a single underscore are reserved by enum and cannot be used; all other
attributes defined within an enumeration will become members of this
enumeration, with the exception of special methods (__str__()
,
__add__()
, etc.), descriptors (methods are also descriptors), and
variable names listed in _ignore_
.
Note: if your enumeration defines __new__()
and/or __init__()
then
any value(s) given to the enum member will be passed into those methods.
See Planet for an example.
Restricted Enum subclassing¶
A new Enum
class must have one base Enum class, up to one concrete
data type, and as many object
-based mixin classes as needed. The
order of these base classes is:
class EnumName([mix-in, ...,] [data-type,] base-enum):
pass
Also, subclassing an enumeration is allowed only if the enumeration does not define any members. So this is forbidden:
>>> 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
その他¶
IntEnum
は enum
モジュールの一部ですが、単独での実装もとても簡単に行なえます:
class IntEnum(int, Enum):
pass
ここでは似たような列挙型の派生を定義する方法を紹介します; 例えば、StrEnum
は int
ではなく str
で複合させたものです。
いくつかのルール:
Enum
のサブクラスを作成するとき、複合させるデータ型は、基底クラスの並びでEnum
自身より先に記述しなければなりません (上記IntEnum
の例を参照)。While
Enum
can have members of any type, once you mix in an additional type, all the members must have values of that type, e.g.int
above. This restriction does not apply to mix-ins which only add methods and don't specify another type.他のデータ型と複合された場合、
value
属性は、たとえ等価であり等価であると比較が行えても、列挙型メンバー自身としては 同じではありません 。%-方式の書式: %s および %r はそれぞれ
Enum
クラスの__str__()
および__repr__()
を呼び出します; その他のコード (IntEnum の %i や %h など) は列挙型のメンバーを複合されたデータ型として扱います。Formatted string literals,
str.format()
, andformat()
will use the mixed-in type's__format__()
unless__str__()
or__format__()
is overridden in the subclass, in which case the overridden methods orEnum
methods will be used. Use the !s and !r format codes to force usage of theEnum
class's__str__()
and__repr__()
methods.
When to use __new__()
vs. __init__()
¶
__new__()
must be used whenever you want to customize the actual value of
the Enum
member. Any other modifications may go in either
__new__()
or __init__()
, with __init__()
being preferred.
For example, if you want to pass several items to the constructor, but only want one of them to be the value:
>>> 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
は用途の大部分をカバーすると予想されますが、そのすべてをカバーできているわけではありません。
ここでは、そのまま、あるいは独自の列挙型を作る例として使える、様々なタイプの列挙型を紹介します。
値の省略¶
多くの用途では、列挙型の実際の値が何かは気にされません。 このタイプの単純な列挙型を定義する方法はいくつかあります:
これらのどの方法を使ってもユーザーに対して、値は重要ではなく、他のメンバーの番号の振り直しをする必要無しに、メンバーの追加、削除、並べ替えが行えるということを示せます。
どの方法を選んでも、(重要でない) 値を隠す 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
To make a more general purpose AutoNumber
, add *args
to the signature:
>>> 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
...
Then when you inherit from AutoNumber
you can write your own __init__
to handle any extra arguments:
>>> 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'
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¶
An example to show the _ignore_
attribute in use:
>>> 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 クラス¶
The EnumMeta
metaclass is responsible for providing the
__contains__()
, __dir__()
, __iter__()
and other methods that
allow one to do things with an Enum
class that fail on a typical
class, such as list(Color) or some_enum_var in Color. EnumMeta
is
responsible for ensuring that various other methods on the final Enum
class are correct (such as __new__()
, __getnewargs__()
,
__str__()
and __repr__()
).
Enum メンバー (インスタンス)¶
Enum メンバーについて最も興味深いのは、それらがシングルトンであるということです。EnumMeta
は Enum
自身を作成し、メンバーを作成し、新しいインスタンスが作成されていないかどうかを確認するために既存のメンバーインスタンスだけを返すカスタム __new__()
を追加します。
細かい点¶
__dunder__
名のサポート¶
__members__
is a read-only ordered mapping of member_name
:member
items. It is only available on the class.
__new__()
が、もし指定されていた場合、列挙型のメンバーを作成し、返します;
そのメンバー の _value_
を適切に設定するのも非常によい考えです。
いったん全てのメンバーが作成されると、それ以降 __new__()
は使われません。
_sunder_
名のサポート¶
_name_
-- メンバー名_value_
-- メンバーの値;__new__
で設定したり、変更したりできます_missing_
-- 値が見付からなかったときに使われる検索関数; オーバーライドされていることがあります_ignore_
-- a list of names, either as alist
or astr
, that will not be transformed into members, and will be removed from the final class_order_
-- used in Python 2/3 code to ensure member order is consistent (class attribute, removed during class creation)_generate_next_value_
-- used by the Functional API and byauto
to get an appropriate value for an enum member; may be overridden
バージョン 3.6 で追加: _missing_
, _order_
, _generate_next_value_
バージョン 3.7 で追加: _ignore_
To help keep Python 2 / Python 3 code in sync an _order_
attribute can
be provided. It will be checked against the actual order of the enumeration
and raise an error if the two do not match:
>>> 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_
注釈
In Python 2 code the _order_
attribute is necessary as definition
order is lost before it can be recorded.
_Private__names¶
Private names will be normal attributes in Python 3.10 instead of either an error
or a member (depending on if the name ends with an underscore). Using these names
in 3.9 will issue a 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
クラスとメンバーの真偽値¶
(int
, str
などのような) 非 Enum
型と複合させた Enum
のメンバーは、その複合された型の規則に従って評価されます;
そうでない場合は、全てのメンバーは True
と評価されます。
メンバーの値に依存する独自の Enum の真偽値評価を行うには、クラスに次のコードを追加してください:
def __bool__(self):
return bool(self.value)
メソッド付きの 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>