An enumeration is a set of symbolic names bound to unique, constant values. Within an enumeration, the values can be compared by identity, and the enumeration itself can be iterated over.

The PEP was accepted by Guido on May 10th, 2013 .

Further discussion in late April 2013 led to the conclusion that enumeration members should belong to the type of their enum: type(Color.red) == Color . Guido has pronounced a decision on this issue , as well as related issues of not allowing to subclass enums , unless they define no enumeration members .

The key dividing issue between Enum and IntEnum is whether comparing to integers is semantically meaningful. For most uses of enumerations, it's a feature to reject comparison to integers; enums that compare to integers lead, through transitivity, to comparisons between enums of unrelated types, which isn't desirable in most cases. For some uses, however, greater interoperability with integers is desired. For instance, this is the case for replacing existing standard library constants (such as socket.AF_INET ) with enumerations.

The idea of adding an enum type to Python is not new - PEP 354 is a previous attempt that was rejected in 2005. Recently a new set of discussions was initiated on the python-ideas mailing list. Many new ideas were proposed in several threads; after a lengthy discussion Guido proposed adding flufl.enum to the standard library . During the PyCon 2013 language summit the issue was discussed further. It became clear that many developers want to see an enum that subclasses int , which can allow us to replace many integer constants in the standard library by enums with friendly string representations, without ceding backwards compatibility. An additional discussion among several interested core developers led to the proposal of having IntEnum as a special case of Enum .

It is possible to simply define a sequence of values of some other basic type, such as int or str , to represent discrete arbitrary values. However, an enumeration ensures that such values are distinct from any others including, importantly, values within other enumerations, and that operations without meaning ("Wednesday times two") are not defined for these values. It also provides a convenient printable representation of enum values without requiring tedious repetition while defining them (i.e. no GREEN = 'green' ).

The properties of an enumeration are useful for defining an immutable, related set of constant values that may or may not have a semantic meaning. Classic examples are days of the week (Sunday through Saturday) and school assessment grades ('A' through 'D', and 'F'). Other examples include error status values and states within a defined process.

We propose to add a module named enum to the standard library. The main type exposed by this module is Enum . Hence, to import the Enum type user code will run:

Creating an Enum Enumerations are created using the class syntax, which makes them easy to read and write. An alternative creation method is described in Functional API. To define an enumeration, subclass Enum as follows: >>> from enum import Enum >>> class Color(Enum): ... red = 1 ... green = 2 ... blue = 3 A note on nomenclature: we call Color an enumeration (or enum) and Color.red , Color.green are enumeration members (or enum members). Enumeration members also have values (the value of Color.red is 1 , etc.) Enumeration members have human readable string representations: >>> print(Color.red) Color.red ...while their repr has more information: >>> print(repr(Color.red)) <Color.red: 1> The type of an enumeration member is the enumeration it belongs to: >>> type(Color.red) <Enum 'Color'> >>> isinstance(Color.green, Color) True >>> Enums also have a property that contains just their item name: >>> print(Color.red.name) red Enumerations support iteration, in definition order: >>> 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 Enumeration members are hashable, so they can be used in dictionaries and sets: >>> apples = {} >>> apples[Color.red] = 'red delicious' >>> apples[Color.green] = 'granny smith' >>> apples {<Color.red: 1>: 'red delicious', <Color.green: 2>: 'granny smith'}

Programmatic access to enumeration members Sometimes it's useful to access members in enumerations programmatically (i.e. situations where Color.red won't do because the exact color is not known at program-writing time). Enum allows such access: >>> Color(1) <Color.red: 1> >>> Color(3) <Color.blue: 3> If you want to access enum members by name, use item access: >>> Color['red'] <Color.red: 1> >>> Color['green'] <Color.green: 2>

Duplicating enum members and values Having two enum members with the same name is invalid: >>> class Shape(Enum): ... square = 2 ... square = 3 ... Traceback (most recent call last): ... TypeError: Attempted to reuse key: square However, two enum members are allowed to have the same value. Given two members A and B with the same value (and A defined first), B is an alias to A. By-value lookup of the value of A and B will return A. By-name lookup of B will also return 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> Iterating over the members of an enum does not provide the aliases: >>> list(Shape) [<Shape.square: 2>, <Shape.diamond: 1>, <Shape.circle: 3>] The special attribute __members__ is an ordered dictionary mapping names to members. It includes all names defined in the enumeration, including the aliases: >>> 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>) The __members__ attribute can be used for detailed programmatic access to the enumeration members. For example, finding all the aliases: >>> [name for name, member in Shape.__members__.items() if member.name != name] ['alias_for_square']

Comparisons Enumeration members are compared by identity: >>> Color.red is Color.red True >>> Color.red is Color.blue False >>> Color.red is not Color.blue True Ordered comparisons between enumeration values are not supported. Enums are not integers (but see IntEnum below): >>> Color.red < Color.blue Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unorderable types: Color() < Color() Equality comparisons are defined though: >>> Color.blue == Color.red False >>> Color.blue != Color.red True >>> Color.blue == Color.blue True Comparisons against non-enumeration values will always compare not equal (again, IntEnum was explicitly designed to behave differently, see below): >>> Color.blue == 2 False

Allowed members and attributes of enumerations The examples above use integers for enumeration values. Using integers is short and handy (and provided by default by the Functional API), but not strictly enforced. In the vast majority of use-cases, one doesn't care what the actual value of an enumeration is. But if the value is important, enumerations can have arbitrary values. Enumerations are Python classes, and can have methods and special methods as usual. If we have this enumeration: 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 Then: >>> 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: all attributes defined within an enumeration will become members of this enumeration, with the exception of __dunder__ names and descriptors ; methods are descriptors too.

Restricted subclassing of enumerations Subclassing an enumeration is allowed only if the enumeration does not define any members. So this is forbidden: >>> class MoreColor(Color): ... pink = 17 ... TypeError: Cannot extend enumerations But this is allowed: >>> class Foo(Enum): ... def some_behavior(self): ... pass ... >>> class Bar(Foo): ... happy = 1 ... sad = 2 ... The rationale for this decision was given by Guido in . Allowing to subclass enums that define members would lead to a violation of some important invariants of types and instances. On the other hand, it makes sense to allow sharing some common behavior between a group of enumerations, and subclassing empty enumerations is also used to implement IntEnum .

IntEnum A variation of Enum is proposed which is also a subclass of int . Members of an IntEnum can be compared to integers; by extension, integer enumerations of different types can also be compared to each other: >>> 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 However they still can't be compared to Enum : >>> class Shape(IntEnum): ... circle = 1 ... square = 2 ... >>> class Color(Enum): ... red = 1 ... green = 2 ... >>> Shape.circle == Color.red False IntEnum values behave like integers in other ways you'd expect: >>> int(Shape.circle) 1 >>> ['a', 'b', 'c'][Shape.circle] 'b' >>> [i for i in range(Shape.square)] [0, 1] For the vast majority of code, Enum is strongly recommended, since IntEnum breaks some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other unrelated enumerations). It should be used only in special cases where there's no other choice; for example, when integer constants are replaced with enumerations and backwards compatibility is required with code that still expects integers.

Other derived enumerations IntEnum will be part of the enum module. However, it would be very simple to implement independently: class IntEnum(int, Enum): pass This demonstrates how similar derived enumerations can be defined, for example a StrEnum that mixes in str instead of int . Some rules: When subclassing Enum, mix-in types must appear before Enum itself in the sequence of bases, as in the IntEnum example above. 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 data type such as int or str .

Pickling Enumerations can be pickled and unpickled: >>> from enum.tests.fruit import Fruit >>> from pickle import dumps, loads >>> Fruit.tomato is loads(dumps(Fruit.tomato)) True The usual restrictions for pickling apply: picklable enums must be defined in the top level of a module, since unpickling requires them to be importable from that module.