[docs] [issue19040] Problems with overriding Enum.__new__

Drekin report at bugs.python.org
Tue Sep 17 12:10:37 CEST 2013

New submission from Drekin:

I tried to implement an Enum variant OptionalEnum such that OptionalEnum(value) leaves value alone and returnes it (if there is no corresponding enum member) rather than raising ValueError. My use case is following: I'm trying to parse some keyboard layout related data. There is a table which maps virtual keys to unicode codepoints, however there are some special values which don't represent a codepoint but the fact that the key is a deadkey and more information is provided in the next table entry. Or that the key produces a ligature. So I wanted to define enums for those special values.

This brought me to the following naive approach:
class OptionalEnum(Enum):
    def __new__(cls, value):
            return super(cls, cls).__new__(cls, value)
        except ValueError:
            return value

This ends with a weird exception. As I ran through enum code I found out that there are actually two flavors of EnumSubclass.__new__. The first one is for precreating the enum members (during creation of EnumSubclass). This is the intended usage. The second flavor is what happens when EnumSubclass(value) is called later. This flavor is represented by Enum.__new__ which returns existing member corresponding to the value or raises ValueError. However this Enum.__new__ is rather special. It doesn't take place in the process of the first flavor, it is explicitly by-passed. On the other hand it is forced behavior of the second flavor since it is explicitly assigned to EnumSubclass.__new__. So there seems to be no way to customize the second flavor (as I tried in my use case).

So could the customization of the second flavor of __new__ be added? (One maybe naive solution would be to let user explicitly define __new_member__ rather than __new__ to customize the first flavor and leave __new__ for the second flavor.) Or could at least be done something with the exceptions produced when one tries to? (The exception in my case was 'TypeError: object() takes no parameters' and was result of having custom __new__ and hence use_args==True but having member_type==object and __new__ not creating member with _value_ attribute so object(*args) was called.)

In any case additional documentation on customizing __new__ could help. There are points like that one should avoid the pattern of falling back to super().__new__ since that is Enum.__new__ which is for something else. Also the custom __new__ should return an object with _value_ attribute or object() with some argument may be called which leads to uninformative exception.

assignee: docs at python
components: Documentation, Library (Lib)
messages: 197979
nosy: Drekin, docs at python
priority: normal
severity: normal
status: open
title: Problems with overriding Enum.__new__
type: behavior
versions: Python 3.4

Python tracker <report at bugs.python.org>

More information about the docs mailing list