如何比较Python中的枚举? [英] How to compare Enums in Python?

查看:162
本文介绍了如何比较Python中的枚举?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

自Python 3.4以来,枚举类存在。



我正在编写一个程序,其中一些常量一个具体的顺序,我想知道哪个方法是最pythonic来比较他们:

 类信息(枚举):
ValueOnly = 0
FirstDerivative = 1
SecondDerivative = 2

现在有一个方法,需要将信息信息与不同的枚举进行比较:

  information = Information.FirstDerivative 
print(value)
如果信息> = Information.FirstDerivative:
print(jacobian)
如果信息> = Information.SecondDerivative:
print(hessian)

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



方法1:使用值:

  if information.value> = Info rmation.FirstDerivative.value:
...

方法2:使用IntEnum: p>

 类信息(IntEnum):
...

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

 类信息: 
ValueOnly = 0
FirstDerivative = 1
SecondDerivative = 2

每种方法都有效,方法1有点冗长,而方法2使用不推荐的IntEnum类,而方法3似乎是Enum被添加之前的方法。



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



感谢任何建议!

解决方案

如果您想使用枚举,则可以使用丰富的比较操作员。使用 functools.total_ordering 类装饰器,您只需要实现一个 __ eq __ 方法以及单个排序,例如。 __ LT __ 。由于 enum.Enum 已经实现了 __ eq __ 这变得更加容易:

 >>> import enum 
>>>从functools import total_ordering
>>>> @total_ordering
... class Grade(enum.Enum):
... A = 5
... B = 4
... C = 3
... D = 2
... F = 1
... def __lt __(self,other):
...如果self .__ class__是其他.__ class__:
... return self.value< other.value
... return NotImplemented
...
>>> Grade.A> = Grade.B
True
>>> Grade.A> = 3
追溯(最近的最后一次呼叫):
文件< stdin>,第1行,< module>
TypeError:不顺序类型:Grade()> = int()

可怕的,可怕的,可以用 IntEnum 发生可怕的事情。它主要包括向后兼容性,枚举过去通过子类化 int 实现。从文档


$ b $对于绝大多数代码,强烈建议使用枚举,因为
IntEnum会打破枚举的一些语义承诺(由
与整数相当,因此由传递给其他无关的
枚举)。它应该仅在特殊情况下使用,其中
没有其他选择;例如,当
枚举代替整数常量时,向后兼容性是
仍然需要整数的代码。


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

 >>> class GradeNum(enum.IntEnum):
... A = 5
... B = 4
... C = 3
... D = 2
... F = 1
...
>>>西装(enum.IntEnum):
... spade = 4
... heart = 3
... diamond = 2
... club = 1
...
>>> GradeNum.A> = GradeNum.B
True
>>> GradeNum.A> = 3
True
>>> GradeNum.B == Suit.spade
True
>>>


Since Python 3.4, the Enum class exists.

I am writing a program, where some constants have a specific order and I wonder which way is the most pythonic to compare them:

class Information(Enum):
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2

Now there is a method, which needs to compare a given information of Information with the different enums:

information = Information.FirstDerivative
print(value)
if information >= Information.FirstDerivative:
    print(jacobian)
if information >= Information.SecondDerivative:
    print(hessian)

The direct comparison does not work with Enums, so there are three approaches and I wonder which one is preferred:

Approach 1: Use values:

if information.value >= Information.FirstDerivative.value:
     ...

Approach 2: Use IntEnum:

class Information(IntEnum):
    ...

Approach 3: Not using Enums at all:

class Information:
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2

Each approach works, Approach 1 is a bit more verbose, while Approach 2 uses the not recommended IntEnum-class, while and Approach 3 seems to be the way one did this before Enum was added.

I tend to use Approach 1, but I am not sure.

Thanks for any advise!

解决方案

You should always implement the rich comparison operaters if you want to use them with an Enum. Using the functools.total_ordering class decorator, you only need to implement an __eq__ method along with a single ordering, e.g. __lt__. Since enum.Enum already implements __eq__ this becomes even easier:

>>> 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()

Terrible, horrible, ghastly things can happen with IntEnum. It was mostly included for backwards-compatibility sake, enums used to be implemented by subclassing int. From the docs:

For the vast majority of code, Enum is strongly recommended, since IntEnum breaks some semantic promises of an enumeration (by being comparable to integers, and thus by transitivity to other unrelated enumerations). It should be used only in special cases where there’s no other choice; for example, when integer constants are replaced with enumerations and backwards compatibility is required with code that still expects integers.

Here's an example of why you don't want to do this:

>>> 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
>>> 

这篇关于如何比较Python中的枚举?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆