259 lines
7.9 KiB
Plaintext
259 lines
7.9 KiB
Plaintext
PEP: 354
|
||
Title: Enumerations in Python
|
||
Version: $Revision$
|
||
Last-Modified: $Date$
|
||
Author: Ben Finney <ben+python@benfinney.id.au>
|
||
Status: Superseded
|
||
Type: Standards Track
|
||
Content-Type: text/x-rst
|
||
Created: 20-Dec-2005
|
||
Python-Version: 2.6
|
||
Post-History: 20-Dec-2005
|
||
Superseded-By: 435
|
||
|
||
|
||
Rejection Notice
|
||
================
|
||
|
||
This PEP has been rejected. This doesn't slot nicely into any of the
|
||
existing modules (like collections), and the Python standard library
|
||
eschews having lots of individual data structures in their own
|
||
modules. Also, the PEP has generated no widespread interest. For
|
||
those who need enumerations, there are cookbook recipes and PyPI
|
||
packages that meet these needs.
|
||
|
||
*Note: this PEP was superseded by* :pep:`435`, *which has been accepted in
|
||
May 2013.*
|
||
|
||
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/reference/datamodel.html#the-standard-type-hierarchy>
|
||
|
||
.. [#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:
|