Updates based on recent enhancements in flufl.enum + some clarifications.

More TODOs remain: importantly, the improved convenience/functional API.
This commit is contained in:
Eli Bendersky 2013-04-02 07:09:55 -07:00
parent e3654917be
commit cb3c841bab
1 changed files with 37 additions and 48 deletions

View File

@ -27,6 +27,12 @@ and from their integer equivalents, supporting use cases such as storing
enumeration values in a database.
Decision
========
TODO: update decision here once pronouncement is made.
Status of discussions
=====================
@ -263,39 +269,9 @@ that expect integers::
>>> int(Colors.blue)
3
You can also convert back to the enumeration value by calling the Enum
You can also convert back to the enumeration value by indexing into the Enum
subclass, passing in the integer value for the item you want::
>>> Colors(1)
<EnumValue: Colors.red [int=1]>
>>> Colors(2)
<EnumValue: Colors.green [int=2]>
>>> Colors(3)
<EnumValue: Colors.blue [int=3]>
>>> Colors(1) is Colors.red
True
The Enum subclass also accepts the string name of the enumeration value::
>>> Colors('red')
<EnumValue: Colors.red [int=1]>
>>> Colors('blue') is Colors.blue
True
You get exceptions though, if you try to use invalid arguments::
>>> Colors('magenta')
Traceback (most recent call last):
...
ValueError: magenta
>>> Colors(99)
Traceback (most recent call last):
...
ValueError: 99
The Enum base class also supports getitem syntax, exactly equivalent to the
class's call semantics::
>>> Colors[1]
<EnumValue: Colors.red [int=1]>
>>> Colors[2]
@ -304,10 +280,16 @@ class's call semantics::
<EnumValue: Colors.blue [int=3]>
>>> Colors[1] is Colors.red
True
The string name of the enumeration value is also accepted::
>>> Colors['red']
<EnumValue: Colors.red [int=1]>
>>> Colors['blue'] is Colors.blue
True
You get exceptions though, if you try to use invalid arguments::
>>> Colors['magenta']
Traceback (most recent call last):
...
@ -357,7 +339,6 @@ Enumeration values are hashable, so they can be used in dictionaries and sets::
red -> red delicious
green -> granny smith
IntEnum
-------
@ -396,9 +377,12 @@ However they still can't be compared to ``Enum``::
>>> Shape.circle == Colors.red
False
For the vast majority of code, ``Enum`` is recommended. Only if a greater
degree of interoperatility with integers is required and ``Enum`` does not
fit the bill, ``IntEnum`` should be used.
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.
Pickling
--------
@ -410,10 +394,11 @@ Enumerations created with the class syntax can also be pickled and unpickled::
>>> Fruit.tomato is loads(dumps(Fruit.tomato))
True
Convenience API
---------------
TODO: update to the new convenience API
You can also create enumerations using the convenience function ``make()``,
which takes an iterable object or dictionary to provide the item names and
values. ``make()`` is a module-level function.
@ -447,7 +432,6 @@ Proposed variations
Some variations were proposed during the discussions in the mailing list.
Here's some of the more popular ones.
Not having to specify values for enums
--------------------------------------
@ -466,7 +450,6 @@ Cons: involves much magic in the implementation, which makes even the
definition of such enums baffling when first seen. Besides, explicit is
better than implicit.
Using special names or forms to auto-assign enum values
-------------------------------------------------------
@ -508,18 +491,24 @@ usages can be divided to two categories: user-code facing constants, and
internal constants.
User-code facing constants like ``os.SEEK_*``, ``socket`` module constants,
decimal rounding modes, HTML error codes could benefit from being enums had
they been implemented this way from the beginning. At this point, however, at
the risk of breaking user code (that relies on the constants' actual values
rather than their meaning) such a change cannot be made. This does not mean
that future uses in the stdlib can't use an enum for defining new user-code
facing constants.
decimal rounding modes and HTML error codes could require backwards
compatibility since user code may expect integers. ``IntEnum`` as described
above provides the required semantics; being a subclass of ``int``, it does not
affect user code that expects integers, while on the other hand allowing
printable representations for enumeration values::
>>> import socket
>>> family = socket.AF_INET
>>> family == 2
True
>>> print(family)
SocketFamily.AF_INET
Internal constants are not seen by user code but are employed internally by
stdlib modules. It appears that nothing should stand in the way of
implementing such constants with enums. Some examples uncovered by a very
partial skim through the stdlib: ``binhex``, ``imaplib``, ``http/client``,
``urllib/robotparser``, ``idlelib``, ``concurrent.futures``, ``turtledemo``.
stdlib modules. These can be implemented with ``Enum``. Some examples
uncovered by a very partial skim through the stdlib: ``binhex``, ``imaplib``,
``http/client``, ``urllib/robotparser``, ``idlelib``, ``concurrent.futures``,
``turtledemo``.
In addition, looking at the code of the Twisted library, there are many use
cases for replacing internal state constants with enums. The same can be said