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