[Python-Dev] PEP 435 -- Adding an Enum type to the Python standard library

Steven D'Aprano steve at pearwood.info
Sun Apr 21 03:29:54 CEST 2013


On 21/04/13 05:42, Barry Warsaw wrote:
> On Apr 13, 2013, at 12:51 PM, Steven D'Aprano wrote:
>
>> I think that's too strong a restriction. I would expect to be able to do this:
>>
>> class Insect(Enum):
>>      wsap = 1  # Oops, needed for backward compatibility, do not remove.
>>      wasp = 1  # Preferred. Use this in new code.
>>      bee = 2
>>      ant = 3
>>
>>
>> Or at the very least:
>>
>> class Insect(Enum):
>>      wasp = wsap = 1
>>      bee = 2
>>      ant = 3
>>
>> What's the justification for this restriction? I have looked in the PEP, and
>> didn't see one.
>
> If you allowed this, there would be no way to look up an enumeration item by
> value.  This is necessary for e.g. storing the value in a database.  If you
> know that the "insect" column is an INTEGER that represents an enumeration
> item of Insect, then you can just store the int value in the column.  To
> reconstitute the actual enumeration item when you read the column back from
> the database, you need to be able to look up the item by value.

I agree that's a good example of a situation where the user might want unique
values. But I don't agree that this is the responsibility of the Enum type
itself. Enums are a mapping from name to value, just like dicts:

d = {'wasp': 1, 'bee': 2, 'ant': 3}

There are use-cases where we might want dicts to be 1:1 too, but we don't force
that restriction on all dicts. Even if I want to reconstruct the key from the
value, doesn't mean that everybody who uses dicts must be prohibited from using
duplicate values. We don't even offer a guaranteed 1:1 mapping type in the
standard library.

Actual real world enums can and do frequently contain duplicate values, I've
previously given examples of such. The ability to have two enums with the same
value is in my opinion not just a Nice To Have but is a Must Have.

With the ability to have duplicate values, enums are the One Obvious Way to
do it. Without it, the decision process becomes more complex: does my
application now, or will it ever, need duplicate values? If there's even a tiny
chance it might need them in the future, I cannot risk getting stuck with an
enum type that prohibits that.

I would argue that it is the responsibility of enums to start with the least
restrictions as is reasonable, and leave additional restrictions up to
subclasses, rather than the other way around. (I'll just quietly mention the
Liskov Substitution Principle here...) If some people need enums to have unique
values, then enforcing that should be their responsibility, and not forced on
all users whether they need that restriction or not.

If there is enough demand for that, then perhaps the enum module could provide a
standard mechanism for enforcing unique values, via a flag, or a subclass, say.
I like the idea of a mixin:

class Insect(UniqueValues, Enum):
     wasp = 1
     bee = 2
     ant = 3


But it should be off by default.


> Currently, you do this:
>
>      >>> my_insect = Insect[database_value]
>
> but if the values are not unique, you have no way to reliably do it.  I don't
> much like APIs which return sequences (either always or "on demand") or rely
> on definition order or some other arbitrary discrimination because I don't
> think any of those are practical in the real world.

Neither do I. I would be perfectly happy for enums to raise ValueError in that
case, and leave it up to the caller to either prevent duplicate values from
occurring, or to deal with the exception in whichever way makes sense for their
application.



> I also recall that duplication was a specific anti-feature in the previous
> python-ideas discussion.  It was thought that this would allow for typos in
> the set of enumeration items to creep in.

Typos occur whether enums allow duplicate values or not. How you deal with
such typos depends on whether you are forced to keep it forever, or can define
a second enum with the same value and deprecate the typo.




-- 
Steven


More information about the Python-Dev mailing list