【问题标题】:Enum in Python doesn't work as expectedPython 中的枚举无法按预期工作
【发布时间】:2015-01-24 11:35:29
【问题描述】:

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

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

所以我在step对象中使用了这个枚举类型,以便他们将其存储在属性分析中,如下:

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 不起作用。

【问题讨论】:

  • 我读了一个文件。我试图提出一个简约的例子,但它工作正常,所以我不知道出了什么问题。
  • 如果我按照您建议的方式进行操作,我会得到AttributeError: static。见this post
  • 哦,我明白了,我尝试了不同的 enum 包。也许您应该将此添加到您的问题中。
  • 有什么不同的枚举包?我正在使用的包在帖子中说明。
  • 那么你如何你设置step.analysis?请在您的问题中添加相关代码。

标签: python python-3.x enums enumeration


【解决方案1】:

在 cmets 中,你说:

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

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

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

但是:

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

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

正如@martineau 在 cmets 中建议的那样,避免此问题的一种方法是改用 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 有什么意义呢?

假设您要枚举两组项目,例如水果和颜色。现在,“橙色”既是一种水果,也是一种颜色。所以我们写:

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

但是现在:

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

但是,从哲学上讲,“橙色”(水果)与“橙色”(颜色)不同!难道我们不能区分这两者吗?在这里,IntEnumint 的子类化对我们不利,因为Fruits.orangeColors.orange 都等同于1。当然,正如我们在上面看到的,Enums 的比较是比较 ids,而不是值。由于Fruits.orangeColors.orange 是唯一的对象,因此它们的比较不相等:

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

这样:

>>> Fruits.orange == Colors.orange
False

我们不再生活在一个你可以在当地杂货店的农产品区找到一些颜色的世界。

【讨论】:

  • 感谢您的回答。我进行了grep 搜索,代码中只有一个点是我创建枚举的位置:fem/definitions.py:Analysis = Enum('Analysis', 'static dynamic')。所以我从definitions.py 文件中导入分析。
  • @aaragon 我敢打赌这仍然是正在发生的事情。如果您检查step.analysisAnalysis.staticid,我猜您会发现它们是不同的。也就是说,它们是两个不同的对象。你在比较你解开的Enums 吗?
  • 你是对的!我没有使用未腌制的枚举。我在分配后检查了 ID:print(id(self.steps[-1].analysis)); print(id(Analysis.static)),它给了我相同的数字:4329054048。后来我做了同样的事情:print(id(step.analysis)); print(id(Analysis.static)),第二个 ID 不同:4393709864。为什么会这样?比较枚举的全部目的是能够对整数值进行比较(来自 C++ 世界)。
  • @aaragon:您可以通过使用派生自intIntEnum 类来避免该问题。
  • 这解决了我的问题,但它并没有解决问题。这是Enum python 类中的错误吗?
【解决方案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

【讨论】:

  • 正好来了。为什么在 python 枚举上的测试是错误的?这是同一个枚举!......啊哈...... - 太混乱了!
【解决方案3】:

对于陷入 Austin Basye 所描述的情况并且无法仅通过更改导入来解决问题的任何人,请尝试使用枚举值。

也就是说,如果obj1.type1 == obj2.type1 为假(但应该为真),请检查obj1.type1.value == obj2.type2.value 是否有效。

在这种情况下,Analysis1.static.value == Analysis2.static.value 应该始终返回正确的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多