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

Nick Coghlan ncoghlan at gmail.com
Sat Apr 27 15:17:36 CEST 2013


On Sat, Apr 27, 2013 at 7:41 AM, Guido van Rossum <guido at python.org> wrote:
> On Fri, Apr 26, 2013 at 11:17 AM, Eli Bendersky <eliben at gmail.com> wrote:
>> In contrast, personally I feel the current proposal in PEP 435 has an appeal
>> from the POV of simplicity. It really is a very nice separation of concerns
>> between enum values and Enum as a container of such values. It even allows
>> significant customization (IntEnum, etc) which is pretty simple to grok. It
>> would be a shame to lose these for the sake of making Python a bit more like
>> Java.
>
> But it's not so much the "like Java" that matters to me. It's the
> realization that for the user who wants to define an enum type with
> some extra functionality, having a single class and putting the
> methods and the items in the same class is the simplest way to do it.
> The Java reference is just to point out that we're not exactly
> breaking new ground here.

A common idiom in some other use cases (like ORMs) is to allow an
inner class to customise behaviour beyond what the basic class syntax
allows. It seems like that may be a good fit here, as a couple of
simple changes should greatly simplify the process of tweaking the
behaviour of the enum items, without adding more complexity to the
implementation:

1. Change the name of "__value_factory__" to something more concise
like "__enumitem__".
2. Make EnumItem and IntEnumItem public classes

(Barry has already noted that the current naming the associated
classes in flufl.enum and PEP 435 isn't quite right, since the
intended terminology is enum for the class, enum item for the labelled
values, and value for the raw unlabelled objects, but the class names
are currently EnumValue and IntEnumValue).

Then, if you want to add custom behaviour to your enum, you would be
able to do use a nested class relatively cleanly:

    class MyEnum(Enum):
        itemA = 1
        itemB = 2

        class __enumitem__(EnumItem):
            def __init__(self, enum, value, name):
                if not name.startswith("item"):
                    raise ValueError("Item name {} doesn't start with
'item'".format(name))
                super().__init__(enum, value, name)
            @property
            def letter(self):
                return self.name[4:]

    class MyExtendedEnum(MyEnum):
        # The custom __enumitem__ is inherited along with the original
attributes
        itemC = 3
        itemD = 4

Furthermore, rather than tweaking isinstance checks, it may make more
sense to support containment testing for enums, such that you can
write things like:

    assert MyEnum.itemA in MyEnum
    assert 1 not in MyEnum

Cheers,
Nick.

--
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-Dev mailing list