Как сравнить перечисления в 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
>>>