Python中的枚举不能按预期工作

时间:2015-01-24 11:35:29

标签: python python-3.x enums enumeration

我在Python的Enum类中发现了一个非常奇怪的行为。所以枚举类型很简单:

from enum import Enum
Analysis = Enum('Analysis', 'static dynamic')

所以我将这个枚举类型用于步骤对象,以便它们将它存储在属性分析中,如下所示:

class Step:
    def __init__(self):
        self.analysis = None
        self.bcs = []

到目前为止非常简单,所以当我在列表中有一些这些步骤时,我会尝试查看枚举类型并且已正确分配。但他们并不平等:

# loop over steps
for s, step in enumerate(kwargs['steps']):
    print(kwargs)
    print(step)
    print(step.analysis)
    print("test for equality: ",(step.analysis == Analysis.static))
    quit()

打印

{'mesh': <fem.mesh.mesh.Mesh object at 0x10614d438>,
 'steps': [<hybrida.fem.step.Step object at 0x10614d278>,
           <hybrida.fem.step.Step object at 0x10616a710>,
           <hybrida.fem.step.Step object at 0x10616a390>]}
Step:
  analysis: Analysis.static
  bcs: [<hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a0f0>,
        <hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a320>,
        <hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a3c8>,
        <hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a470>,
        <hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a518>,
        <hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a5c0>,
        <hybrida.fem.conditions.dirichlet.Dirichlet object at 0x10616a668>]
Analysis.static
test for equality:  False

这是不正确的,但我对如何调试它没有任何想法。

更新

根据@martineau的建议,我创建了一个IntEnum,这解决了我的问题。然而,我不明白为什么正常的Enum不起作用。

2 个答案:

答案 0 :(得分:12)

在评论中,您说:

  

输入文件包含许多步骤,每次添加新步骤I   必须设置分析类型

如果我理解正确,您每次添加新步骤时都会创建一个新的Enum对象。这可能就是您看到&#34; bug&#34;的原因。尽管具有相同的名称和顺序,但两个不同Enum个对象的值不一定相等。例如:

import enum
Analysis1 = enum.Enum("Analysis", "static dynamic")
Analysis2 = enum.Enum("Analysis", "static dynamic")

可是:

>>> Analysis1.static == Analysis2.static
False

这是因为我没有为Enum个对象定义相等运算符,因此使用了检查id的默认行为。

正如@martineau在评论中建议的那样,避免此问题的一种方法是使用IntEnum类型,即子类int,因此根据值的类型定义相等运算符。 Enum,而不是id

import enum
Analysis1 = enum.IntEnum("Analysis", "static dynamic")
Analysis2 = enum.IntEnum("Analysis", "static dynamic")

然后:

>>> Analysis1.static == Analysis2.static
True

为什么Enum IntEnum

乍一看,IntEnum 总是我们想要的东西。那么Enum是什么意思?

假设您要枚举两组项目,例如水果和颜色。现在,&#34;橙&#34;既是水果又是颜色。所以我们写道:

Fruits = enum.IntEnum("Fruits", "orange apple lemon")
Colors = enum.IntEnum("Colors", "orange red blue")

但现在:

>>> Fruits.orange == Colors.orange
True

但是,从哲学上讲,&#34; orange&#34; (水果)与&#34;橙色&#34; (颜色)!难道我们不能区分这两者吗?在这里,int的{​​{1}}的子类化对我们起作用,因为IntEnumFruits.orange都等同于Colors.orange。当然,正如我们上面所见,1 s的比较比较Enum s,而不是值。由于idFruits.orange是唯一对象,因此它们不会相等:

Colors.orange

那样:

Fruits = enum.Enum("Fruits", "orange apple lemon")
Colors = enum.Enum("Colors", "orange red blue")

我们不再生活在一些颜色是您可以在当地杂货店的产品部分找到的东西的世界。

答案 1 :(得分:2)

万一其他人发现我们之后,我们也会遇到同样的问题。我们可以将其追溯到绝对进口和相对进口的无意混合,其方式类似于以下所述。

# File: package/module/analysis_types.py
Analysis = enum.Enum("Analysis", "static dynamic")
# File: package/module/static_thing.py
from .analysis_types import Analysis

class StaticThing:
    ...
    analysis = Analysis.static
    ...
# File: package/module/static_thing_test.py
from package.module.static_thing import StaticThing
from .analysis_types import Analysis

# This throws an AssertionError because as
#  id(StaticThing.analysis) != id(Analysis.static)
assert StaticThing.analysis == Analysis.static

通过以下更改恢复了预期的行为:

# File: package/module/static_thing_test.py
from .static_thing import StaticThing
from .analysis_types import Analysis

# This does NOT throw an AssertionError because as
#  id(StaticThing.analysis) == id(Analysis.static)
assert StaticThing.analysis == Analysis.static