Python 在枚举构造函数中使用super()时发生NameError

Python 在枚举构造函数中使用super()时发生NameError,python,python-2.7,enums,super,nameerror,Python,Python 2.7,Enums,Super,Nameerror,我正在使用Python 2.7.10和enum34库。我正在努力做到以下几点: 从枚举导入枚举 类别Foo(枚举): 定义初始化(自): 通过 分类栏(Foo): 值=1 定义初始值(自身,值): 超级(棒,自我)。\uuuu初始化 运行此代码时,我收到错误name错误:未定义全局名称“Bar”。有人能解释一下我为什么会收到这个错误,以及是否可以调用枚举子类的父构造函数吗?提前谢谢你 编辑:Olivier Melançon的回溯(编辑路径名): Traceback (most recent c

我正在使用Python 2.7.10和
enum34
库。我正在努力做到以下几点:

从枚举导入枚举
类别Foo(枚举):
定义初始化(自):
通过
分类栏(Foo):
值=1
定义初始值(自身,值):
超级(棒,自我)。\uuuu初始化
运行此代码时,我收到错误
name错误:未定义全局名称“Bar”
。有人能解释一下我为什么会收到这个错误,以及是否可以调用枚举子类的父构造函数吗?提前谢谢你

编辑: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
回溯(最近一次呼叫最后一次):
文件“/…/test.py”,第9行,在
分类栏(Foo):
文件“/…/lib/python2.7/site packages/enum/_init__.py”,第236行,新__
枚举成员。初始化(*args)
文件“/…/test.py”,第13行,在__
超级(棒,自我)。\uuuu初始化
NameError:未定义全局名称“Bar”
进程已完成,退出代码为1

问题在于
Bar.VALUE.\uuuu init\uuuu
Bar
存在之前被调用

您可以看到这种情况在何处发生,但即使不查看代码,它也必须以这种方式工作:
Enum
类的全部要点是,它的枚举成员是常量值,作为类的属性,同时也是类的实例

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

通常,如果您有枚举层次结构,那么您只需要在“叶”类中输入值,而在非叶类中输入行为。然而,在中明确记录的唯一限制是非叶类中没有值,因此从技术上讲,您尝试执行的操作应该是合法的,即使这是不寻常的,并且从来没有明确打算工作


如果您使用的是Python3,有一个非常简单的解决方法:只使用
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


最有可能的是,无论您实际想要完成什么,都可以以更好的方式完成,而无需进行任何更改。但是,由于您的玩具示例没有完成任何任务,因此没有更多的内容可供展示。

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

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

(请注意,
self.\uuuuu类
已经取代了
Bar

我认为即使在Python 3.4+中,这也不起作用。IIRC,仅当只有基类有行为且只有子类有枚举成员时,子类化枚举类才有效。我想补充的是,如果我将类和对象提供给super,则在Python3中会出现相同的错误,但如果我只调用super()则不会。这段代码的目的是什么?为什么要在
Foo
中覆盖
Enum
的初始值设定项以不执行任何操作,为什么要在
Bar
中覆盖它以获取一个值并忽略它?为@OlivierMelançon发布的回溯。@user9027325如果您试图做的事情没有记录在案但实际上不起作用,除了你想要的“某种行为”之外,我不能假设其他任何事情,我不能告诉你如何做到这一点。我最多可以解释一下为什么你的代码不起作用(我想这正是我在上一篇评论中所说的),然后让你想出一个不同的设计。这就是你想要的吗?是的,
\uuuuuu new\uuuuuu
\uuuu init\uuuuuu
都是在创建成员时被调用的,这是在类正式存在之前。@EthanFurman似乎任何对
\uuu new\uuuuuuu
感到好奇的人都会知道,即使不扫描代码,它也必须在
\uuuuu init\uuuu
之前被调用,正确的?但也许发生的事情足够复杂,值得一提?老实说,我对此没有直觉;如果你认为我应该提到
\uuuuu new\uuuuuu
,我会编辑这个问题(当然,你也可以编辑它)。@EthanFurman还有,你的“类正式存在”似乎有点笨拙,但我在回答中的措辞(只需通过引用名称
而不是类来绕开这个问题…)看起来更糟。有什么更好的表达方式吗?这实际上是一个非常笨拙的术语。更好的解释是,在元类完成对类的处理之前,名称
Bar
不会绑定到类,但与普通Python类不同,在普通Python类中,实例是创建和初始化的/after/class处理和创建的,
Enum
在类被完全处理之前/创建并初始化成员。Python3中的魔法
super()
可能没有这个问题,我还没有测试过。@EthanFurman是的,我在寻找一种方法,用一个简短的句子说出来,这比我在答案中所说的要好,但可能没有办法做到这一点。同时,magic
super
没有这个问题,因为
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。有关详细信息,请参阅或。但我可以理解为什么你不会测试它,因为这是一个奇怪的用例。