如何在Python中比较枚举?

时间:2016-09-01 09:42:29

标签: python enums compare

自Python 3.4起,Enum类就存在了。

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

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

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

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

直接比较不适用于Enums,因此有三种方法,我想知道哪一种更受欢迎:

方法1:使用值:

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

方法2:使用IntEnum:

class Information(IntEnum):
    ...

方法3:根本不使用Enums:

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

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

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

感谢您的任何建议!

4 个答案:

答案 0 :(得分:26)

如果要将它们与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()

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

  

对于绝大多数代码,强烈建议使用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
>>> 

答案 1 :(得分:6)

之前我没遇到过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

答案 2 :(得分:0)

结合上面的一些想法,您可以将 enum.Enum 子类化以使其与字符串/数字相当,然后在此类上构建您的枚举:

import numbers
import enum


class EnumComparable(enum.Enum):
    def __gt__(self, other):
        try:
            return self.value > other.value
        except:
            pass
        try:
            if isinstance(other, numbers.Real):
                return self.value > other
        except:
            pass
        return NotImplemented

    def __lt__(self, other):
        try:
            return self.value < other.value
        except:
            pass
        try:
            if isinstance(other, numbers.Real):
                return self.value < other
        except:
            pass
        return NotImplemented

    def __ge__(self, other):
        try:
            return self.value >= other.value
        except:
            pass
        try:
            if isinstance(other, numbers.Real):
                return self.value >= other
            if isinstance(other, str):
                return self.name == other
        except:
            pass
        return NotImplemented

    def __le__(self, other):
        try:
            return self.value <= other.value
        except:
            pass
        try:
            if isinstance(other, numbers.Real):
                return self.value <= other
            if isinstance(other, str):
                return self.name == other
        except:
            pass
        return NotImplemented

    def __eq__(self, other):
        if self.__class__ is other.__class__:
            return self == other
        try:
            return self.value == other.value
        except:
            pass
        try:
            if isinstance(other, numbers.Real):
                return self.value == other
            if isinstance(other, str):
                return self.name == other
        except:
            pass
        return NotImplemented

答案 3 :(得分:-2)

我的实现方式略有不同。只需转到源代码enum.py并找到Enum的类定义,然后添加以下源代码:

def __gt__(self, other):
    if self.value > other.value:
        return True
    return False

    # 2020/03/18 Naive Implementations of He Zhu
def __lt__(self, other):
    if self.value < other.value:
        return True
    return False

    # 2020/03/18 Naive Implementations of He Zhu
def __ge__(self, other):
    if self.value >= other.value:
        return True
    return False

    # 2020/03/18 Naive Implementations of He Zhu
def __le__(self, other):
    if self.value <= other.value:
        return True
    return False

def __eq__(self, other):
    return self.value == other.value

然后,您的Python将支持简单的枚举类型比较