В этом руководстве вы узнаете о псевдонимах элементов перечисления в Python и о том, как использовать декоратор enum unique для обеспечения уникальности значений элементов.
Что такое псевдонимы элементов перечислений?
По определению значения членов перечисления уникальны. Однако вы можете создавать разные имена элементов с одинаковыми значениями.
Например, следующий код определяет перечисление Color:
from enum import Enum
class Color(Enum):
RED = 1
CRIMSON = 1
SALMON = 1
GREEN = 2
BLUE = 3
В этом примере перечисление Color содержит элементы RED, CRIMSON и SALMON с одинаковым значением 1. Когда вы определяете несколько членов перечисления с одинаковыми значениями, Python создает не разные члены, а псевдонимы. RED является основным элементом, а CRIMSON и SALMON являются псевдонимами члена RED.
Следующие операторы возвращают значение True, поскольку CRIMSON и SALMON являются членами RED:
print(Color.RED is Color.CRIMSON) print(Color.RED is Color.SALMON)
Выход:
True True
Когда вы ищете элемент по значению, вы всегда получаете основной элемент, а не псевдонимы. Например, следующий оператор возвращает элемент RED:
print(Color(1))
Выход:
Color.RED
При переборе перечисления с псевдонимами вы получите только основные члены, а не псевдонимы. Пример:
for color in Color:
print(color)
Он возвращает только три члена:
Color.RED Color.GREEN Color.BLUE
Чтобы получить все члены, включая псевдонимы, вам нужно использовать свойство __member__ класса перечисления. Например:
from enum import Enum
from pprint import pprint
class Color(Enum):
RED = 1
CRIMSON = 1
SALMON = 1
GREEN = 2
BLUE = 3
pprint(Color.__members__)
Выход:
mappingproxy({'BLUE': <Color.BLUE: 3>,
'CRIMSON': <Color.RED: 1>,
'GREEN': <Color.GREEN: 2>,
'RED': <Color.RED: 1>,
'SALMON': <Color.RED: 1>})
Как ясно видно из выходных данных, CRIMSON и SALMON ссылаются на один и тот же объект, на который ссылается член RED:
<Color.RED: 1>
Когда использовать псевдонимы перечислений
Псевдонимы перечисления могут быть полезны в некоторых ситуациях. Например, предположим, что вам приходится иметь дело с API двух разных систем. Каждая система имеет свой статус ответа, имеющий то же значение, что показано в следующей таблице:
| Система 1 | Система 2 | Значение |
|---|---|---|
| REQUESTING | PENDING | Запрос находится в обработке |
| OK | FULFILLED | Запрос успешно выполнен |
| NOT_OK | REJECTED | Запрос не выполнен |
Чтобы стандартизировать коды состояния этих систем, вы можете использовать псевдонимы перечисления следующим образом:
| Ваша система | Система 1 | Система 2 | Значение |
|---|---|---|---|
| IN_PROGRESS | REQUESTING | PENDING | Запрос находится в обработке |
| SUCCESS | OK | FULFILLED | Запрос успешно выполнен |
| ERROR | NOT_OK | REJECTED | Запрос не выполнен |
Следующий код определяет перечисление ResponseStatus с псевдонимами:
from enum import Enum
class ResponseStatus(Enum):
# in progress
IN_PROGRESS = 1
REQUESTING = 1
PENDING = 1
# success
SUCCESS = 2
OK = 2
FULFILLED = 2
# error
ERROR = 3
NOT_OK = 3
REJECTED = 3
Ниже сравнивается код ответа системы 1, чтобы проверить, был ли запрос успешным или нет:
code="OK"
if ResponseStatus[code] is ResponseStatus.SUCCESS:
print('The request completed successfully')
Выход:
The request completed successfully
Аналогичным образом вы можете проверить код ответа от системы 2, чтобы убедиться, что запрос был успешным:
code="FULFILLED"
if ResponseStatus[code] is ResponseStatus.SUCCESS:
print('The request completed successfully')
Выход:
print('The request completed successfully')
Декоратор @enum.unique
Чтобы определить перечисление без псевдонимов, вы можете осторожно использовать уникальные значения для его членов. Например:
from enum import Enum
class Day(Enum):
MON = 'Monday'
TUE = 'Tuesday'
WED = 'Wednesday'
THU = 'Thursday'
FRI = 'Friday'
SAT = 'Saturday'
SUN = 'Sunday'
Но вы можете случайно использовать одни и те же значения для двух членов, например:
class Day(Enum):
MON = 'Monday'
TUE = 'Monday'
WED = 'Wednesday'
THU = 'Thursday'
FRI = 'Friday'
SAT = 'Saturday'
SUN = 'Sunday'
В этом примере TUE является псевдонимом члена MON, чего вы, возможно, не ожидаете. Чтобы гарантировать, что перечисление не имеет псевдонима, вы можете использовать декоратор @enum.unique из модуля enum.
Когда вы используете декоратор @enum.unique, Python выдает исключение, если перечисление имеет псевдонимы.
Например, следующее вызовет ValueError:
import enum
from enum import Enum
@enum.unique
class Day(Enum):
MON = 'Monday'
TUE = 'Monday'
WED = 'Wednesday'
THU = 'Thursday'
FRI = 'Friday'
SAT = 'Saturday'
SUN = 'Sunday'
Ошибка:
ValueError: duplicate values found in <enum 'Day'>: TUE -> MON
