cpython: e7a01c7f69fe (original) (raw)

new file mode 100644 --- /dev/null +++ b/Doc/library/enum.rst @@ -0,0 +1,542 @@ +:mod:enum --- Support for enumerations +======================================== + +.. module:: enum +.. :synopsis: enumerations are sets of symbolic names bound to unique, constant

+ +A note on nomenclature: we call :class:Color an enumeration (or enum) +and :attr:Color.red, :attr:Color.green are enumeration members (or +enum members). Enumeration members also have values (the value of +:attr:Color.red is 1, etc.) + +Enumeration members have human readable string representations:: +

+ +...while their repr has more information:: +

+ +The type of an enumeration member is the enumeration it belongs to:: +

+ +Enum members also have a property that contains just their item name:: +

+ +Enumerations support iteration, in definition order:: +

+ +Enumeration members are hashable, so they can be used in dictionaries and sets:: +

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

+ +If you want to access enum members by name, use item access:: +

+ + +Duplicating enum members and values +----------------------------------- + +Having two enum members with the same name is invalid:: +

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

+ +Iterating over the members of an enum does not provide the aliases:: +

+ +The special attribute __members__ is an ordered dictionary mapping names +to members. It includes all names defined in the enumeration, including the +aliases:: +

+ +The __members__ attribute can be used for detailed programmatic access to +the enumeration members. For example, finding all the aliases:: +

+ +Comparisons +----------- + +Enumeration members are compared by identity:: +

+ +Ordered comparisons between enumeration values are not supported. Enum +members are not integers (but see IntEnum_ below):: +

+ +Equality comparisons are defined though:: +

+ +Comparisons against non-enumeration values will always compare not equal +(again, class:IntEnum was explicitly designed to behave differently, see +below):: +

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

+ +Then:: +

+ +The rules for what is allowed are as follows: sunder names (starting and +ending 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 dunder names and descriptors (methods +are also descriptors). + +Note: if your enumeration defines :meth:__new__ and/or :meth:__init__ then +whatever value(s) were given to the enum member will be passed into those +methods. See Planet_ for an example. + + +Restricted subclassing of enumerations +-------------------------------------- + +Subclassing an enumeration is allowed only if the enumeration does not define +any members. So this is forbidden:: +

+ +But this is allowed:: +

+ +Allowing subclassing of 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. +(See OrderedEnum_ for an example.) + + +Pickling +-------- + +Enumerations can be pickled and unpickled:: +

+ +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. + +.. warning:: +

+ + +Functional API +-------------- + +The :class:Enum class is callable, providing the following functional API:: +

+ +The semantics of this API resemble :class:namedtuple. The first argument +of the call to :class:Enum is the name of the enumeration. + +The second argument is the source of enumeration member names. It can be a +whitespace-separated string of names, a sequence of names, a sequence of +2-tuples with key/value pairs, or a mapping (e.g. dictionary) of names to +values. The last two options enable assigning arbitrary values to +enumerations; the others auto-assign increasing integers starting with 1. A +new class derived from :class:Enum is returned. In other words, the above +assignment to :class:Animal is equivalent to:: +

+ +Pickling enums created with the functional API can be tricky as frame stack +implementation details are used to try and figure out which module the +enumeration is being created in (e.g. it will fail if you use a utility +function in separate module, and also may not work on IronPython or Jython). +The solution is to specify the module name explicitly as follows:: +

+ +Derived Enumerations +==================== + +IntEnum +------- + +A variation of :class:Enum is provided which is also a subclass of +:class:int. Members of an :class:IntEnum can be compared to integers; +by extension, integer enumerations of different types can also be compared +to each other:: +

+ +However, they still can't be compared to standard :class:Enum enumerations:: +

+ +:class:IntEnum values behave like integers in other ways you'd expect:: +

+ +For the vast majority of code, :class:Enum is strongly recommended, +since :class: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. + + +Others +------ + +While :class:IntEnum is part of the :mod:enum module, it would be very +simple to implement independently:: +

+ +This demonstrates how similar derived enumerations can be defined; for example +a :class:StrEnum that mixes in :class:str instead of :class:int. + +Some rules: + +1. When subclassing :class:Enum, mix-in types must appear before

+ +Interesting examples +==================== + +While :class:Enum and :class:IntEnum are expected to cover the majority of +use-cases, they cannot cover them all. Here are recipes for some different +types of enumerations that can be used directly, or as examples for creating +one's own. + + +AutoNumber +---------- + +Avoids having to specify the value for each enumeration member:: +

+ + +UniqueEnum +---------- + +Raises an error if a duplicate member name is found instead of creating an +alias:: +

+ + +OrderedEnum +----------- + +An ordered enumeration that is not based on :class:IntEnum and so maintains +the normal :class:Enum invariants (such as not being comparable to other +enumerations):: +

+ + +Planet +------ + +If :meth:__new__ or :meth:__init__ is defined the value of the enum member +will be passed to those methods:: +

new file mode 100644 --- /dev/null +++ b/Lib/enum.py @@ -0,0 +1,465 @@ +"""Python Enumerations""" + +import sys +from collections import OrderedDict +from types import MappingProxyType + +all = ['Enum', 'IntEnum'] + + +class _RouteClassAttributeToGetattr:

+

+

+

+

+

+ + +def _is_dunder(name):

+ + +def _is_sunder(name):

+ + +def _make_class_unpicklable(cls):

+ + +class _EnumDict(dict):

+

+

+

+

+

+

+

+ + +# Dummy value for Enum as EnumMeta explicity checks for it, but of course until +# EnumMeta finishes running the first time the Enum class doesn't exist. This +# is also why there are checks in EnumMeta like if Enum is not None +Enum = None + + +class EnumMeta(type):

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ + +class Enum(metaclass=EnumMeta):

+

+

+

+

+

+

+

+

+

+

+

+ + +class IntEnum(int, Enum):

new file mode 100644 --- /dev/null +++ b/Lib/test/test_enum.py @@ -0,0 +1,921 @@ +import enum +import unittest +from collections import OrderedDict +from pickle import dumps, loads, PicklingError +from enum import Enum, IntEnum + +# for pickle tests +try:

+except Exception as exc:

+ +try:

+except Exception as exc:

+ +try:

+except Exception as exc:

+ +# for pickle test and subclass tests +try:

+except Exception as exc:

+ +try:

+except Exception as exc:

+ +try:

+except Exception as exc:

+ +# for doctests +try:

+except Exception:

+ +class TestEnum(unittest.TestCase):

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ +

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+

+ +

+

+ + +if name == 'main':

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -381,6 +381,8 @@ Library