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):
try:
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@python
components: Documentation, Library (Lib)
messages: 197979
nosy: Drekin, docs@python
priority: normal
severity: normal
status: open
title: Problems with overriding Enum.__new__
type: behavior
versions: Python 3.4
_______________________________________
Python tracker <[email protected]>
<http://bugs.python.org/issue19040>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com