在枚举构造函数中使用 super() 时出现名称错误



我正在使用Python 2.7.10和enum34库。我正在尝试执行以下操作:

from enum import Enum

class Foo(Enum):
def __init__(self):
pass

class Bar(Foo):
VALUE = 1
def __init__(self, value):
super(Bar, self).__init__()

运行此代码时,我收到错误NameError: global name 'Bar' is not defined。有人可以帮助解释为什么我会收到此错误以及是否可以调用枚举子类的父构造函数吗?提前谢谢你!

编辑: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

问题是Bar.VALUE.__init__Bar存在之前就被调用了。

你可以在EnumMeta.__new__中看到这种情况发生的位置,但即使不看代码,它也几乎必须以这种方式工作:Enum类的全部意义在于它的枚举成员是常量值,充当类的属性,同时也是类的实例。

在这种情况下,此代码将在 stdlibenum模块的 3.4+ 中产生完全相同的错误,并在多个第三方enum替换中产生类似的错误。

通常,如果您有 Enum 层次结构,则应该只将值放在"叶"类中,而行为只放在非叶类中。但是,枚举的受限子类中实际明确记录的唯一限制是非叶类中没有值,因此从技术上讲,您尝试执行的操作应该是合法的,即使它不寻常并且从未明确打算工作。


如果你使用的是Python 3,有一个非常简单的解决方法:只使用super()而不是super(Bar, self),这并不重要,Bar还不存在。

在 Python 2 中,由于这不可行,因此您需要手动模拟super。对于完全通用性,这意味着编写代码以遍历mro等等,但由于包含两个或多个Enum类的多重继承无论如何都不起作用,因此只需静态硬编码即可:

def __init__(self, value):
Foo.__init__(self)

或者,如果您更改设计以将所有行为放在非叶类中,这也将起作用:

class Foo(Enum):
def __init__(self):
pass
class Bar(Foo):
def __init__(self, value):
super(Bar, self).__init__()
class Baz(Bar):
VALUE = 1

最有可能的是,无论您实际尝试完成什么,都可以以更好的方式完成,而无需进行任何这些更改。但是,由于您的玩具示例没有完成任何事情,因此没有什么可展示的了。

若要解决名称Bar在创建成员时尚未绑定到BarEnum的问题,请使用:

super(self.__class__, self).__init__()

(请注意,self.__class__已取代Bar(

最新更新