如何在Python中比较枚举?

Seb*_*erk 20 python enums compare

从Python 3.4开始,Enum该类存在.

我正在编写一个程序,其中一些常量有一个特定的顺序,我想知道哪种方式是比较它们最pythonic:

class Information(Enum):
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2
Run Code Online (Sandbox Code Playgroud)

现在有一种方法,需要将给定informationInformation与不同的枚举进行比较:

information = Information.FirstDerivative
print(value)
if information >= Information.FirstDerivative:
    print(jacobian)
if information >= Information.SecondDerivative:
    print(hessian)
Run Code Online (Sandbox Code Playgroud)

直接比较不适用于Enums,所以有三种方法,我想知道哪一种是首选的:

方法1:使用值:

if information.value >= Information.FirstDerivative.value:
     ...
Run Code Online (Sandbox Code Playgroud)

方法2:使用IntEnum:

class Information(IntEnum):
    ...
Run Code Online (Sandbox Code Playgroud)

方法3:根本不使用枚举:

class Information:
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2
Run Code Online (Sandbox Code Playgroud)

每种方法都有效,方法1有点冗长,而方法2使用不推荐的IntEnum类,而方法3似乎就是在添加Enum之前这样做的方式.

我倾向于使用方法1,但我不确定.

谢谢你的任何建议!

jua*_*aga 30

如果要将它们与a一起使用,则应始终实现丰富的比较运算符Enum.使用functools.total_ordering类装饰器,您只需要实现一个__eq__方法以及单个排序,例如__lt__.由于enum.Enum已经实现,__eq__这变得更加容易:

>>> import enum
>>> from functools import total_ordering
>>> @total_ordering
... class Grade(enum.Enum):
...   A = 5
...   B = 4
...   C = 3
...   D = 2
...   F = 1
...   def __lt__(self, other):
...     if self.__class__ is other.__class__:
...       return self.value < other.value
...     return NotImplemented
... 
>>> Grade.A >= Grade.B
True
>>> Grade.A >= 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unorderable types: Grade() >= int()
Run Code Online (Sandbox Code Playgroud)

可怕的,可怕的,可怕的事情都可能发生IntEnum.它主要包含在向后兼容性方面,以前通过子类实现的枚举int.来自文档:

对于绝大多数代码,强烈建议使用Enum,因为IntEnum打破了枚举的一些语义承诺(通过与整数相比较,因此通过对其他无关枚举的传递性).它只应在没有其他选择的特殊情况下使用; 例如,当整数常量被枚举替换时,需要向后兼容性仍需要整数的代码.

以下是您不想这样做的原因示例:

>>> class GradeNum(enum.IntEnum):
...   A = 5
...   B = 4
...   C = 3
...   D = 2
...   F = 1
... 
>>> class Suit(enum.IntEnum):
...   spade = 4
...   heart = 3
...   diamond = 2
...   club = 1
... 
>>> GradeNum.A >= GradeNum.B
True
>>> GradeNum.A >= 3
True
>>> GradeNum.B == Suit.spade
True
>>> 
Run Code Online (Sandbox Code Playgroud)

  • 很好的描述,非常感谢。只有一个问题:您“返回 NotImplemented”,而不是“引发 NotImplemented”。是否存在一般规则,何时使用 return 以及何时使用 raise? (3认同)
  • @SebastianWerk嗯,你不能'提出NotImplemented`,因为它不是一个例外.它是一个内置的单身人士.请参阅[docs](https://docs.python.org/3.5/library/constants.html#NotImplemented),它适用于富比较运算符的特殊情况.根据[docs](https://docs.python.org/2/library/exceptions.html#exceptions.NotImplementedError)的`NotImplementedError`,当"抽象方法在需要派生时引发此异常时"用于覆盖方法的类." (3认同)
  • **优秀的答案,**好先生.这种方法简洁 - 虽然效率较低 - 是[官方Python文档](https://docs.python.org/3/library/enum.html#orderedenum)中详述的`OrderedEnum`类的替代方法.虽然手动实现所有比较运算符的`OrderedEnum`解决方案_is_更快,但上面给出的`@total_ordering`解决方案有其优点.简洁是一种吃力不讨好的美德.相关地,有没有人知道为什么`OrderedEnum`只是记录而不是添加到`enum`模块? (3认同)
  • @SebastianWerk另外,请看这个问题:http://stackoverflow.com/questions/878943/why-return-notimplemented-instead-of-raising-notimplementederror (2认同)
  • 是否有一个 python `Enum` 构造或类似的实际上有点 .. _works_ ?添加 @total_ordering 并实现比较运算符_不_应该需要我们自己编写代码。这是太多的样板。 (2认同)

nig*_*222 11

我之前没有遇到过Enum所以我扫描了文档(https://docs.python.org/3/library/enum.html)...并找到了OrderedEnum(第8.13.13.2节)这不是你想要的?来自doc:

>>> class Grade(OrderedEnum):
...     A = 5
...     B = 4
...     C = 3
...     D = 2
...     F = 1
...
>>> Grade.C < Grade.A
True
Run Code Online (Sandbox Code Playgroud)

  • 似乎无法在 Python 3.6 中导入,`ImportError: 无法导入名称 'OrderedEnum'`?**编辑:** 看起来这是一个“有趣的示例”,实际上并不在标准 python 库中。您需要从文档中复制代码片段才能使用它。 (4认同)
  • OrderedEnum 的文档已移至此处:https://docs.python.org/3/howto/enum.html#orderedenum (2认同)