自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,但我不确定。
感谢您的任何建议!
答案 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将支持简单的枚举类型比较