245 lines
7.4 KiB
Plaintext
245 lines
7.4 KiB
Plaintext
|
PEP: 354
|
|||
|
Title: Enumerations in Python
|
|||
|
Version: $Revision$
|
|||
|
Last-Modified: $Date$
|
|||
|
Author: Ben Finney <ben+python@benfinney.id.au>
|
|||
|
Status: Draft
|
|||
|
Type: Standards Track
|
|||
|
Content-Type: text/x-rst
|
|||
|
Created: 20-Dec-2005
|
|||
|
Python-Version: 2.6
|
|||
|
Post-History: 20-Dec-2005
|
|||
|
|
|||
|
|
|||
|
Abstract
|
|||
|
========
|
|||
|
|
|||
|
This PEP specifies an enumeration data type for Python.
|
|||
|
|
|||
|
An enumeration is an exclusive set of symbolic names bound to
|
|||
|
arbitrary unique values. Values within an enumeration can be iterated
|
|||
|
and compared, but the values have no inherent relationship to values
|
|||
|
outside the enumeration.
|
|||
|
|
|||
|
|
|||
|
Motivation
|
|||
|
==========
|
|||
|
|
|||
|
The properties of an enumeration are useful for defining an immutable,
|
|||
|
related set of constant values that have a defined sequence but no
|
|||
|
inherent 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.
|
|||
|
|
|||
|
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, and that operations without meaning
|
|||
|
("Wednesday times two") are not defined for these values.
|
|||
|
|
|||
|
|
|||
|
Specification
|
|||
|
=============
|
|||
|
|
|||
|
An enumerated type is created from a sequence of arguments to the
|
|||
|
type's constructor::
|
|||
|
|
|||
|
>>> Weekdays = enum('sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat')
|
|||
|
>>> Grades = enum('A', 'B', 'C', 'D', 'F')
|
|||
|
|
|||
|
Enumerations with no values are meaningless. The exception
|
|||
|
``EnumEmptyError`` is raised if the constructor is called with no
|
|||
|
value arguments.
|
|||
|
|
|||
|
The values are bound to attributes of the new enumeration object::
|
|||
|
|
|||
|
>>> today = Weekdays.mon
|
|||
|
|
|||
|
The values can be compared::
|
|||
|
|
|||
|
>>> if today == Weekdays.fri:
|
|||
|
... print "Get ready for the weekend"
|
|||
|
|
|||
|
Values within an enumeration cannot be meaningfully compared except
|
|||
|
with values from the same enumeration. The comparison operation
|
|||
|
functions return ``NotImplemented`` [#CMP-NOTIMPLEMENTED]_ when a
|
|||
|
value from an enumeration is compared against any value not from the
|
|||
|
same enumeration or of a different type::
|
|||
|
|
|||
|
>>> gym_night = Weekdays.wed
|
|||
|
>>> gym_night.__cmp__(Weekdays.mon)
|
|||
|
1
|
|||
|
>>> gym_night.__cmp__(Weekdays.wed)
|
|||
|
0
|
|||
|
>>> gym_night.__cmp__(Weekdays.fri)
|
|||
|
-1
|
|||
|
>>> gym_night.__cmp__(23)
|
|||
|
NotImplemented
|
|||
|
>>> gym_night.__cmp__("wed")
|
|||
|
NotImplemented
|
|||
|
>>> gym_night.__cmp__(Grades.B)
|
|||
|
NotImplemented
|
|||
|
|
|||
|
This allows the operation to succeed, evaluating to a boolean value::
|
|||
|
|
|||
|
>>> gym_night = Weekdays.wed
|
|||
|
>>> gym_night < Weekdays.mon
|
|||
|
False
|
|||
|
>>> gym_night < Weekdays.wed
|
|||
|
False
|
|||
|
>>> gym_night < Weekdays.fri
|
|||
|
True
|
|||
|
>>> gym_night < 23
|
|||
|
False
|
|||
|
>>> gym_night > 23
|
|||
|
True
|
|||
|
>>> gym_night > "wed"
|
|||
|
True
|
|||
|
>>> gym_night > Grades.B
|
|||
|
True
|
|||
|
|
|||
|
Coercing a value from an enumeration to a ``str`` results in the
|
|||
|
string that was specified for that value when constructing the
|
|||
|
enumeration::
|
|||
|
|
|||
|
>>> gym_night = Weekdays.wed
|
|||
|
>>> str(gym_night)
|
|||
|
'wed'
|
|||
|
|
|||
|
The sequence index of each value from an enumeration is exported as an
|
|||
|
integer via that value's ``index`` attribute::
|
|||
|
|
|||
|
>>> gym_night = Weekdays.wed
|
|||
|
>>> gym_night.index
|
|||
|
3
|
|||
|
|
|||
|
An enumeration can be iterated, returning its values in the sequence
|
|||
|
they were specified when the enumeration was created::
|
|||
|
|
|||
|
>>> print [str(day) for day in Weekdays]
|
|||
|
['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
|
|||
|
|
|||
|
Values from an enumeration are hashable, and can be used as dict
|
|||
|
keys::
|
|||
|
|
|||
|
>>> plans = {}
|
|||
|
>>> plans[Weekdays.sat] = "Feed the horse"
|
|||
|
|
|||
|
The normal usage of enumerations is to provide a set of possible
|
|||
|
values for a data type, which can then be used to map to other
|
|||
|
information about the values::
|
|||
|
|
|||
|
>>> for report_grade in Grades:
|
|||
|
... report_students[report_grade] = \
|
|||
|
... [s for s in students if students.grade == report_grade]
|
|||
|
|
|||
|
|
|||
|
Rationale -- Other designs considered
|
|||
|
=====================================
|
|||
|
|
|||
|
All in one class
|
|||
|
----------------
|
|||
|
|
|||
|
Some implementations have the enumeration and its values all as
|
|||
|
attributes of a single object or class.
|
|||
|
|
|||
|
This PEP specifies a design where the enumeration is a container, and
|
|||
|
the values are simple comparables. It was felt that attempting to
|
|||
|
place all the properties of enumeration within a single class
|
|||
|
complicates the design without apparent benefit.
|
|||
|
|
|||
|
|
|||
|
Metaclass for creating enumeration classes
|
|||
|
------------------------------------------
|
|||
|
|
|||
|
The enumerations specified in this PEP are instances of an ``enum``
|
|||
|
type. Some alternative designs implement each enumeration as its own
|
|||
|
class, and a metaclass to define common properties of all
|
|||
|
enumerations.
|
|||
|
|
|||
|
One motivation for having a class (rather than an instance) for each
|
|||
|
enumeration is to allow subclasses of enumerations, extending and
|
|||
|
altering an existing enumeration. A class, though, implies that
|
|||
|
instances of that class will be created; it is difficult to imagine
|
|||
|
what it means to have separate instances of a "days of the week"
|
|||
|
class, where each instance contains all days. This usually leads to
|
|||
|
having each class follow the Singleton pattern, further complicating
|
|||
|
the design.
|
|||
|
|
|||
|
In contrast, this PEP specifies enumerations that are not expected to
|
|||
|
be extended or modified. It is, of course, possible to create a new
|
|||
|
enumeration from the string values of an existing one, or even
|
|||
|
subclass the ``enum`` type if desired.
|
|||
|
|
|||
|
|
|||
|
Values related to other types
|
|||
|
-----------------------------
|
|||
|
|
|||
|
Some designs express a strong relationship to some other value, such
|
|||
|
as a particular integer or string, for each enumerated value.
|
|||
|
|
|||
|
This results in using such values in contexts where the enumeration
|
|||
|
has no meaning, and unnecessarily complicates the design. The
|
|||
|
enumerated values specified in this PEP export the values used to
|
|||
|
create them, and can be compared for equality with any other value,
|
|||
|
but sequence comparison with values outside the enumeration is
|
|||
|
explicitly not implemented.
|
|||
|
|
|||
|
|
|||
|
Hiding attributes of enumerated values
|
|||
|
--------------------------------------
|
|||
|
|
|||
|
A previous design had the enumerated values hiding as much as possible
|
|||
|
about their implementation, to the point of not exporting the string
|
|||
|
key and sequence index.
|
|||
|
|
|||
|
The design in this PEP acknowledges that programs will often find it
|
|||
|
convenient to know the enumerated value's enumeration type, sequence
|
|||
|
index, and string key specified for the value. These are exported by
|
|||
|
the enumerated value as attributes.
|
|||
|
|
|||
|
|
|||
|
Implementation
|
|||
|
==============
|
|||
|
|
|||
|
This design is based partly on a recipe [#ENUM-RECIPE]_ from the
|
|||
|
Python Cookbook.
|
|||
|
|
|||
|
The PyPI package ``enum`` [#ENUM-PACKAGE]_ provides a Python
|
|||
|
implementation of the data types described in this PEP.
|
|||
|
|
|||
|
|
|||
|
References and Footnotes
|
|||
|
========================
|
|||
|
|
|||
|
.. [#CMP-NOTIMPLEMENTED]
|
|||
|
The ``NotImplemented`` return value from comparison operations
|
|||
|
signals the Python interpreter to attempt alternative comparisons
|
|||
|
or other fallbacks.
|
|||
|
<http://docs.python.org/ref/types.html#l2h-29>
|
|||
|
|
|||
|
.. [#ENUM-RECIPE]
|
|||
|
"First Class Enums in Python", Zoran Isailovski,
|
|||
|
Python Cookbook recipe 413486
|
|||
|
<http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/413486>
|
|||
|
|
|||
|
.. [#ENUM-PACKAGE]
|
|||
|
Python Package Index, package ``enum``
|
|||
|
<http://cheeseshop.python.org/pypi/enum/>
|
|||
|
|
|||
|
|
|||
|
Copyright
|
|||
|
=========
|
|||
|
|
|||
|
This document has been placed in the public domain.
|
|||
|
|
|||
|
|
|||
|
..
|
|||
|
Local Variables:
|
|||
|
mode: indented-text
|
|||
|
indent-tabs-mode: nil
|
|||
|
sentence-end-double-space: t
|
|||
|
fill-column: 70
|
|||
|
End:
|