在枚举构造函数中使用 super() 时出现 NameError
NameError when using super() in enum constructor
我正在使用 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
class 是它的枚举成员是常量值,作为 class 的属性同时也是它的实例。
因此,此代码将在 3.4+ 中使用 stdlib enum
模块产生完全相同的错误,并在多个第三方 enum
替换时产生类似的错误。
一般来说,如果你有枚举层次结构,你应该只把值放在 "leaf" class 中,行为只放在非叶 class 中es。但是,Restricted subclassing of enumerations 中实际明确记录的唯一限制是非叶 classes 中没有值,因此从技术上讲,您尝试做的事情应该是合法的,即使它不寻常并且从未明确打算工作。
如果您使用的是 Python 3,则有一个非常简单的解决方法:只需使用 super()
而不是 super(Bar, self)
,这比 Bar
更重要还不存在。
在Python2中,由于不行,需要手动模拟super
。对于完全的一般性,这意味着编写代码来遍历 mro
等等,但是由于包括两个或更多 Enum
classes 的多重继承无论如何都不会起作用,你'只需对其进行静态硬编码就可以了:
def __init__(self, value):
Foo.__init__(self)
或者,如果您更改设计以将所有行为放在非叶 classes 中,那也将起作用:
class Foo(Enum):
def __init__(self):
pass
class Bar(Foo):
def __init__(self, value):
super(Bar, self).__init__()
class Baz(Bar):
VALUE = 1
最有可能的是,无论您实际尝试完成什么,都可以以更好的方式完成,而无需进行任何这些更改。但是由于您的玩具示例没有完成任何事情,因此没有更多内容可以展示。
要解决名称 Bar
在创建成员时尚未绑定到 Bar
Enum
的问题,请使用:
super(self.__class__, self).__init__()
(注意 self.__class__
已经取代了 Bar
)
我正在使用 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
class 是它的枚举成员是常量值,作为 class 的属性同时也是它的实例。
因此,此代码将在 3.4+ 中使用 stdlib enum
模块产生完全相同的错误,并在多个第三方 enum
替换时产生类似的错误。
一般来说,如果你有枚举层次结构,你应该只把值放在 "leaf" class 中,行为只放在非叶 class 中es。但是,Restricted subclassing of enumerations 中实际明确记录的唯一限制是非叶 classes 中没有值,因此从技术上讲,您尝试做的事情应该是合法的,即使它不寻常并且从未明确打算工作。
如果您使用的是 Python 3,则有一个非常简单的解决方法:只需使用 super()
而不是 super(Bar, self)
,这比 Bar
更重要还不存在。
在Python2中,由于不行,需要手动模拟super
。对于完全的一般性,这意味着编写代码来遍历 mro
等等,但是由于包括两个或更多 Enum
classes 的多重继承无论如何都不会起作用,你'只需对其进行静态硬编码就可以了:
def __init__(self, value):
Foo.__init__(self)
或者,如果您更改设计以将所有行为放在非叶 classes 中,那也将起作用:
class Foo(Enum):
def __init__(self):
pass
class Bar(Foo):
def __init__(self, value):
super(Bar, self).__init__()
class Baz(Bar):
VALUE = 1
最有可能的是,无论您实际尝试完成什么,都可以以更好的方式完成,而无需进行任何这些更改。但是由于您的玩具示例没有完成任何事情,因此没有更多内容可以展示。
要解决名称 Bar
在创建成员时尚未绑定到 Bar
Enum
的问题,请使用:
super(self.__class__, self).__init__()
(注意 self.__class__
已经取代了 Bar
)