如何在Python中比较枚举?

如何在Python中比较枚举?,python,python-3.x,enums,compare,Python,Python 3.x,Enums,Compare,自Python 3.4以来,就存在Enum类 我正在编写一个程序,其中一些常量有一个特定的顺序,我想知道哪种方式比较它们最为方便: class Information(Enum): ValueOnly = 0 FirstDerivative = 1 SecondDerivative = 2 现在有一种方法,需要将信息的给定信息与不同的枚举进行比较: information = Information.FirstDerivative print(value) if inf

自Python 3.4以来,就存在
Enum

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

class Information(Enum):
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2
现在有一种方法,需要将
信息
的给定
信息
与不同的枚举进行比较:

information = Information.FirstDerivative
print(value)
if information >= Information.FirstDerivative:
    print(jacobian)
if information >= Information.SecondDerivative:
    print(hessian)
直接比较不适用于枚举,因此有三种方法,我想知道哪种方法更可取:

方法1:使用价值观:

if information.value >= Information.FirstDerivative.value:
     ...
方法2:使用IntEnum:

class Information(IntEnum):
    ...
方法3:根本不使用枚举:

class Information:
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2
每种方法都有效,方法1更详细一些,而方法2使用不推荐的IntEnum类,而方法3似乎是添加Enum之前的方法

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


谢谢你的建议

我以前没有遇到过Enum,所以我扫描了文档()。。。找到OrderedEnum(第8.13.13.2节)这不是你想要的吗?从文档:

>>> class Grade(OrderedEnum):
...     A = 5
...     B = 4
...     C = 3
...     D = 2
...     F = 1
...
>>> Grade.C < Grade.A
True
>等级(OrderedEnum):
...     A=5
...     B=4
...     C=3
...     D=2
...     F=1
...
>>>C级
如果要将富比较运算符与
枚举一起使用,则应始终实现它们。使用
functools.total\u ordering
类装饰器,您只需要实现一个
\uu eq\uuu
方法和一个单独的排序,例如
\uu lt\uuu
。由于
enum.enum
已经实现了
\uuuuu eq\uuuu
,这就变得更加容易了:

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

结合上述一些思想,您可以将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
导入编号
导入枚举
类枚举(enum.enum):
定义(自身、其他):
尝试:
返回self.value>other.value
除:
通过
尝试:
如果isinstance(其他,数字.实数):
返回self.value>other
除:
通过
返回未执行
定义(自身、其他):
尝试:
返回self.value=其他.value
除:
通过
尝试:
如果isinstance(其他,数字.实数):
返回self.value>=其他
如果存在(其他,str):
返回self.name==other
除:
通过
返回未执行
定义(自我、其他):
尝试:

返回自我。价值很好的描述,非常感谢。只有一个问题:您
返回NotImplemented
,而不是
提出NotImplemented
。什么时候使用return,什么时候使用raise,有没有一般的规则?@SebastianWerk好吧,你不能
raisenotimplemented
,因为这不是一个例外。它是一个内置的单体。请参见,这是rich比较运算符的特例。根据,当“抽象方法需要派生类重写该方法时,应引发此异常”时,存在
未实现错误
。@SebastianWerk还请参见此问题:回答很好,先生。这种方法是一种简洁的方法,虽然效率较低,但可以替代中详述的
orderedum
类。虽然手动实现所有比较运算符的
orderedum
解决方案速度稍快,但上面给出的
@total_ordering
解决方案有其优点。简洁是吃力不讨好的美德。与此相关的是,有人知道为什么
OrderedEnum
只是被记录而不是添加到
enum
模块中吗?是否有python
enum
构造或类似的构造实际上有点。。作品添加@total_排序并实现比较运算符并不是我们必须自己编写代码的事情。这是太多的陈词滥调了。你能引用“不推荐的IntEnum类”吗?3.7.1版的文档一点也不反对它。当然,从文档中可以看出:“对于大多数新代码,强烈建议使用Enum和Flag,因为IntEnum和IntFlag破坏了枚举的一些语义承诺(通过与整数相比较,从而传递到其他不相关的枚举).IntEnum和IntFlag仅应在Enum和Flag不起作用的情况下使用;例如,当整数常量替换为枚举时,或用于与其他系统的互操作性。“方法1适合我,谢谢!由于未修复的Python错误,这种方法不起作用:您应该始终覆盖比较器方法,如eq和lt@asu没有未修复的错误,该线程中的问题与
Enum
本身无关,而且在任何情况下,该示例都会覆盖比较运算符。在Python 3.6中似乎无法导入,导入错误:无法导入名称“OrderedEnum”
?编辑:看起来这是一个“有趣的示例”,实际上不在标准python库中。您需要从文档中复制代码段才能使用它。
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