[Python-Dev] PEP 435 - ref impl disc 2

Nick Coghlan ncoghlan at gmail.com
Sun May 5 10:08:36 CEST 2013


On Sun, May 5, 2013 at 5:21 PM, Ethan Furman <ethan at stoneleaf.us> wrote:
> When NamedInt goes looking for _name, it finds the one on `x`, not the one
> on `x.value`.

There's also the code in enum_type.__call__ that ensures Enum.__repr__
and Enum.__str__ are used in preference to those from the value type.
(Specifically, the code at
https://bitbucket.org/stoneleaf/ref435/src/758d43b9f7327cd61dc2e45050539b6b5db1c4e3/ref435.py?at=default#cl-152
that ignores __repr__ and __str__ from non-Enum types)

I think this needs to be documented more clearly - if you want to keep
a custom __repr__ or __str__ when mixing Enum (or an Enum subclass)
with another type, then you need to explicitly set them in your
subclass. (e.g. in Glenn's case, setting "__repr__ =
NamedValue.__repr__")

I'm OK with magic to get the kind of enum behaviour we want, but I'm
not OK with *black* magic that we don't explain. There should be an
advanced section in the enum docs which explains these edge cases in
the way the enum metaclass interacts with the normal class machinery.

That said, I'm also fairly sure the current code is incorrect: I
believe it does the wrong thing when an Enum subclass further
customises __repr__, __str__ or __new__.

The more reasonable logic to me seems to be to figure out the "first
enum base" and the "first non-enum base" based on:

   enum_bases = [base for base in enum_class.mro() if issubclass(base, Enum)]
   non_enum_bases = [base for base in enum_class.mro() if not
issubclass(base, Enum)]

Then, if the current __new__, __str__ or __repr__ implementation is
the same as that for the first non-enum base, we replace it with the
impl from the first enum base.

Cheers,
Nick.

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


More information about the Python-Dev mailing list