Как сравнить перечисления в Python?

начиная с Python 3.4,Enum класс существует.

Я пишу программу, где некоторые константы имеют определенный порядок и интересно, какой путь является наиболее подходящие для Python, чтобы сравнить их:

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

теперь есть метод, который должен сравнить данный information of Information С различными перечислениями:

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, похоже, так же, как это было сделано до добавления перечисления.

Я предпочитаю использовать подход 1, но я не уверен.

Спасибо за любой совет!

2 ответов


я столкнулся с перечислением раньше, поэтому я просмотрел документ (https://docs.python.org/3/library/enum.html)... и нашел OrderedEnum (раздел 8.13.13.2) разве это не то, что вы хотите? От Дока:

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

вы всегда должны реализовать богатые операторы сравнения, если вы хотите использовать их с Enum. С помощью functools.total_ordering Class decorator, вам нужно только реализовать __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:

для подавляющего большинства кода настоятельно рекомендуется перечисление, так как 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
>>>