I am using Python 2.7.10 with the enum34
library. I am trying to do the following:
from enum import Enum
class Foo(Enum):
def __init__(self):
pass
class Bar(Foo):
VALUE = 1
def __init__(self, value):
super(Bar, self).__init__()
When this code is run, I receive the error NameError: global name 'Bar' is not defined
. Could someone help explain why I receive this error and if it's possible to call the parent constructor of an enum subclass? Thank you in advance!
Edit: Traceback (with path names redacted) for Olivier Melançon:
Traceback (most recent call last):
File "/.../test.py", line 9, in <module>
class Bar(Foo):
File "/.../lib/python2.7/site-packages/enum/__init__.py", line 236, in __new__
enum_member.__init__(*args)
File "/.../test.py", line 13, in __init__
super(Bar, self).__init__()
NameError: global name 'Bar' is not defined
Process finished with exit code 1
The problem is that Bar.VALUE.__init__
is being called before Bar
exists.
You can see where this happens in EnumMeta.__new__
, but even without looking at the code, it pretty much has to work this way: the whole point of an Enum
class is that its enumeration members are constant values that act as attributes of the class while also being instances of it.
In that, this code will produce the exact same error in 3.4+ with the stdlib enum
module, and similar errors with multiple third-party enum
replacements.
In general, if you have Enum hierarchies at all, you're expected to put values only in the "leaf" classes and behavior only in the non-leaf classes. However, the only restriction that's actually explicitly documented in Restricted subclassing of enumerations is no values in non-leaf classes, so technically what you're trying to do should be legal, even if it's unusual and was never explicitly intended to work.
If you were using Python 3, there's a pretty easy workaround: just using super()
instead of super(Bar, self)
, and it doesn't matter than Bar
doesn't exist yet.
In Python 2, since that isn't doable, you need to manually simulate super
. For full generality, that means writing the code to walk the mro
and so on, but since multiple inheritance including two or more Enum
classes isn't going to work anyway, you'll be fine just hardcoding it statically:
def __init__(self, value):
Foo.__init__(self)
Alternatively, if you change your design to put all the behavior in non-leaf classes, that will also work:
class Foo(Enum):
def __init__(self):
pass
class Bar(Foo):
def __init__(self, value):
super(Bar, self).__init__()
class Baz(Bar):
VALUE = 1
Most likely, whatever you're actually trying to accomplish could be done in a better way without requiring either of these changes. But since your toy example doesn't accomplishes anything, there's nothing more to show.