Reputation: 37
I'm trying translate some code from python 2 to python 3 and had trouble with this code:
from enum import Enum, EnumMeta
class KeyCode(Enum):
A = 1
B = 2
C = 3
class KeyMeta(EnumMeta):
def __new__(mcs, name, bases, dct):
dct.update({e.name: e.value for e in KeyCode})
return super(KeyMeta, mcs).__new__(mcs, name, bases, dct)
class Key(Enum, metaclass=KeyMeta):
pass
print(repr(Key.A))
The problem is that for python2 Key.A
is enum < Key.A: 1>
, whereas for python3 it is < class 'int'>
.
Upvotes: 1
Views: 738
Reputation: 1121904
In Python 3, the dct
object is not a regular dictionary, but a subclass dedicated to helping create enums, set via the __prepare__
attribute of the metaclass. It's update()
method, however, is not altered from the base dictionary.
It normally expects members to be set via it's __setitem__
method (e.g. dct[name] = value
); do so in your __new__
method too:
class KeyMeta(EnumMeta):
def __new__(mcs, name, bases, dct):
for e in KeyCode:
dct[e.name] = e.value
return super(KeyMeta, mcs).__new__(mcs, name, bases, dct)
Now each of the names A
, B
and C
are recorded as being enum member names and the EnumMeta
class takes it from there. Without using the specialised __setitem__
implementation, the names are seen as some other type of attribute instead.
With the above change you get the expected output:
>>> class Key(Enum, metaclass=KeyMeta):
... pass
...
>>> Key.A
<Key.A: 1>
The same for e in KeyCode:
loop will continue to work in Python 2 as well.
Upvotes: 1