Python 3.4では、標準ライブラリenum
に列挙ライブラリがありました。 Python 2.4〜2.7(さらには3.1〜3.3)で動作するenum
のバックポートを取得できます。pypiでは enum34 です。
しかし、私たちはこの新しいモジュールなしでかなり長い間うまくいくことができました。
私は、他の言語の列挙型の目的について一般的な考えを持っています。 Pythonでは、次のようにベアクラスを使用し、これを列挙型として参照することが一般的です。
class Colors:
blue = 1
green = 2
red = 3
これをAPIで使用して、値の正規表現を作成できます。例:
function_of_color(Colors.green)
これに批判がある場合、それは変更可能であり、反復することはできません(簡単に)、そしてどのように整数のセマンティクス2
を知るのですか?
次に、名前付きタプルのようなものを使用することができると思いますが、これは不変です?
>>> Colors = namedtuple('Colors', 'blue green red')
>>> colors = Colors('blue', 'green', 'red')
>>> colors
Colors(blue='blue', green='green', red='red')
>>> list(colors)
['blue', 'green', 'red']
>>> len(colors)
3
>>> colors.blue
'blue'
>>> colors.index(colors.blue)
0
Namedtupleの作成は少し冗長です(各名前を2回記述する必要があります)。色の「数」を取得することも少し洗練されていません(colors
を2回記述する必要があります)。文字列を使用して値のチェックを行う必要がありますが、これは少し効率が低下します。
列挙に戻ります。
列挙型の目的は何ですか?彼らは言語に対してどのような価値を生み出しますか?それらをいつ使用し、いつ使用を避けるべきですか?
列挙型の目的は何ですか?彼らは言語に対してどのような価値を生み出しますか?それらをいつ使用し、いつ使用を避けるべきですか?
EnumタイプがPython via PEP 435 になりました。指定された理由は次のとおりです。
列挙のプロパティは、セマンティックな意味を持つ場合と持たない場合がある不変の関連する定数値のセットを定義するのに役立ちます。
この目的で数字と文字列を使用する場合、それらは "magic numbers" または "magic strings"として特徴付けられます。数字にセマンティクスが含まれることはめったになく、文字列は簡単に混同されます(大文字、スペル、スネーク、キャメルケースなど)。
曜日や学校の成績は、この種の価値のコレクションの例です。
docs の例を次に示します。
_from enum import Enum
class Color(Enum):
red = 1
green = 2
blue = 3
_
ベアクラスのように、これはnamedtupleの例よりもはるかに読みやすくエレガントです。また、不変であり、以下に示すようにさらに利点があります。
_>>> type(Color.red)
<enum 'Color'>
>>> isinstance(Color.green, Color)
True
_
これにより、Enum定義でメンバーの機能を定義できます。値に関する機能の定義は、他の従来の方法で実現できますが、非常に洗練されていません。
文字列表現は人間が読める形式ですが、reprにはさらに情報があります。
_>>> print(Color.red)
Color.red
>>> print(repr(Color.red))
<Color.red: 1>
_
これは、マジックナンバーの改善であり、名前付きタプルの文字列よりも優れている可能性があります。
列挙型は、namedtupleのような反復をサポートしますが、むき出しのクラスではありません):
_>>> for color in Color:
print(color)
Color.red
Color.green
Color.blue
_
___members__
_属性は、enumの名前をそれぞれのenumオブジェクトにマッピングするOrderedDict
です(namedtupleの_asdict()
関数に似ています)。
列挙型をシリアル化および逆シリアル化できます(誰かがこれを心配している場合)。
_>>> import pickle
>>> color.red is pickle.loads(pickle.dumps(color.red))
True
_
これは、ベアクラスにはない素晴らしい機能であり、namedtuple
にエイリアスがあることを伝えるのは難しいでしょう。
_class Color(Enum):
red = 1
green = 2
blue = 3
really_blue = 3
_
エイリアスは正規名の後にありますが、どちらも同じです:
_>>> Color.blue is Color.really_blue
True
_
値の衝突を避けるためにエイリアスを禁止する必要がある場合は、_enum.unique
_デコレーター(厳密に支配的な機能)を使用します。
is
で行われた比較列挙型はis
を使用してテストすることを目的としています。これは、プロセス内の単一オブジェクトのIDをすばやくチェックするものです。
_>>> Color.red is Color.red
True
>>> Color.red is Color.blue
False
>>> Color.red is not Color.blue
True
_
同等性のテストも機能しますが、is
との同一性のテストが最適です。
Enumクラスは、通常のPythonタイプとは異なるセマンティクスを持ちます。Enumの値はEnumのインスタンスであり、それらの値のメモリ内のシングルトンです-インスタンス化する他の目的はありません。
_>>> Color.red is Color('red')
_
これは心に留めておくことが重要です。おそらくマイナス面ですが、この次元で比較することはリンゴとオレンジを比較することです。
Enumクラスはメンバーが作成される順序を知っていますが、enumは順序付けられているとは見なされません。列挙される可能性のあるものの多くは自然な順序を持たないため、これは機能です。したがって、順序は任意です。
ただし、列挙型の順序を指定できます(次のセクションを参照)。
宣言されたメンバーでEnumをサブクラス化することはできませんが、動作を共有するメンバーを宣言しないEnumをサブクラス化できますcanのOrderedEnumレシピを参照してください docs )。
これは機能です-メンバーでEnumをサブクラス化することはほとんど意味がありませんが、ここでも比較はリンゴとオレンジです。
enum.Enum
_を使用すべきですか?これは、Pythonの新しい標準列挙です。共同編集者は、列挙型がこれらの列挙型のように動作することを期待します。
任意のデータの代わりに、正規名を使用するように明示的に指定するコード内の列挙データの正規ソースがある場所であればどこでも使用します。
たとえば、コード内で、ユーザーが_"Green"
_、_"green"
_、2、または_"Greene"
_ではなく、_Color.green
_であると宣言する場合、enum.Enumオブジェクトを使用します。明示的かつ具体的です。
ドキュメント には多くの例とレシピがあります。
自分で転がしたり、人々に魔法の数字や文字列を推測させたりするのを止めてください。それらを避けないでください。それらを受け入れます。
ただし、歴史的な理由で列挙型メンバーが整数である必要がある場合、同じモジュールからのIntEnum
があり、同じ動作をしますが、組み込みのint
をサブクラス化するため整数でもありますEnum
をサブクラス化する前。 IntEnum
のヘルプから:
_class IntEnum(builtins.int, Enum)
_
intEnum値がint
のインスタンスとしてテストされることがわかります。