Enum — перечисления в Python
В этом уроке вы узнаете о перечислении в Python и о том, как его эффективно использовать.
- Что такое перечисление в Python?
- Членство и равенство
- Хеширование элементов перечисления
- Доступ к элементам по имени и значению
- Как перебирать члены перечисления
- Перечисление неизменяемо
- Наследование перечисления
- Пример с перечислением в Python
Что такое перечисление в Python?
По определению перечисление — это набор членов, которым связаны уникальные константные значения. Перечисления в Python часто называют enum.
Python предоставляет вам модуль enum, содержащий тип Enum для определения новых перечислений. И вы определяете новый тип перечисления, создавая подкласс класса Enum.
В следующем примере показано, как создать перечисление под названием Color:
from enum import Enum class Color(Enum): RED = 1 GREEN = 2 BLUE = 3
Как это работает.
- Сначала импортируйте тип Enum из модуля enum:
from enum import Enum
- Во-вторых, определите класс Color, который наследуется от типа Enum:
class Color(Enum):
- В-третьих, определите члены перечисления Color:
RED = 1 GREEN = 2 BLUE = 3
Обратите внимание, что члены перечисления являются константами. Поэтому их имена по традиции пишутся заглавными буквами.
В этом примере Color является перечислением. RED, GREEN и BLUE являются членами перечисления Color. Они имеют связанные значения 1, 2 и 3.
Ниже показано, что тип Color.RED — это перечисление Color:
print(type(Color.RED))
Выход:
<enum 'Color'>
Color.RED также является экземпляром перечисления Color:
print(isinstance(Color.RED, Color))
Выход:
True
И у него есть атрибуты name и value:
print(Color.RED.name) print(Color.RED.value)
Выход:
RED 1
Членство и равенство
Чтобы проверить, включен ли элемент в перечисление, вы используете оператор in. Например:
if Color.RED in Color: print('Yes')
Выход:
Yes
Чтобы сравнить два элемента перечисления, вы можете использовать оператор is или ==. Например:
if Color.RED is Color.BLUE: print('red is blue') else: print('red is not blue')
Выход:
red is not blue
Обратите внимание, что член перечисления и связанное с ним значение не равны. Следующий пример возвращает False:
if Color.RED == 1: print('Color.RED == 1') else: print('Color.RED != 1')
Выход:
Color.RED != 1
Хеширование элементов перечисления
Члены перечисления всегда хешируются. Это означает, что вы можете использовать их как ключи в словаре или как элементы набора.
В следующем примере используются члены перечисления Color в словаре:
rgb = { Color.RED: '#ff0000', Color.GREEN: '#00ff00', Color.BLUE: '#0000ff' }
Доступ к элементам по имени и значению
Типичный способ доступа к элементу перечисления — использовать синтаксис точечной записи (.), как вы видели до сих пор:
Color.RED
Поскольку Enum реализует метод __getitem__, вы также можете использовать синтаксис квадратных скобок [] для получения элемента по его имени.
Например, в следующем примере используется синтаксис квадратных скобок [] для получения члена RED перечисления Color по его имени:
print(Color['RED'])
Выход:
Color.RED
Поскольку перечисление является вызываемым, вы можете получить элемент по его значению. Например, следующая команда возвращает элемент RED перечисления Color по его значению:
print(Color(1))
Выход:
Color.RED
Следующее выражение возвращает значение True, поскольку оно обращается к одному и тому же элементу перечисления, используя имя и значение:
print(Color['RED'] == Color(1))
Выход:
True
Как перебирать члены перечисления
Перечисления являются итерируемыми, поэтому вы можете перебирать их с помощью цикла for. Например:
for color in Color: print(color)
Выход:
Color.RED Color.GREEN Color.BLUE
Обратите внимание, что порядок элементов такой же, как и в определении перечисления.
Кроме того, вы можете использовать функцию list() для возврата списка членов перечисления:
print(list(Color))
Выход:
[<Color.RED: 1>, <Color.GREEN: 2>, <Color.BLUE: 3>]
Перечисление неизменяемо
Перечисления неизменяемы. Это означает, что вы не можете добавлять или удалять элементы после определения перечисления. И вы также не можете изменить значения членов.
В следующем примере предпринимается попытка назначить новый элемент перечислению Color, что приводит к возникновению ошибки TypeError:
Color['YELLOW'] = 4
Ошибка:
TypeError: 'EnumMeta' object does not support item assignment
В следующем примере предпринимается попытка изменить значение члена RED перечисления Color и возникает ошибка AttributeError:
Color.RED.value = 100
Выход:
AttributeError: can't set attribute
Наследование перечисления
Перечисление не может быть унаследовано, если оно не содержит членов. Следующий пример работает нормально, поскольку перечисление Color не содержит элементов:
class Color(Enum): pass class RGB(Color): RED = 1 GREEN = 2 BLUE = 3
Однако следующий пример не будет работать, поскольку перечисление RGB имеет члены:
class RGBA(RGB): ALPHA = 4
Ошибка:
TypeError: Cannot extend enumerations
Пример с перечислением в Python
В следующем примере определяется перечисление ResponseStatus:
class ResponseStatus(Enum): PENDING = 'pending' FULFILLED = 'fulfilled' REJECTED = 'rejected'
Предположим, вы получили ответ на HTTP-запрос со следующей строкой:
response = '''{ "status":"fulfilled" }'''
И вы хотите найти перечисление ResponseStatus по статусу. Для этого вам нужно преобразовать строку ответа в словарь и получить значение статуса:
import json data = json.loads(response) status = data['status']
Затем вы ищете член перечисления ResponseStatus по значению статуса:
print(ResponseStatus(status))
Выход:
PromiseStatus.FULFILLED
Вот полная программа:
from enum import Enum import json class ResponseStatus(Enum): PENDING = 'pending' FULFILLED = 'fulfilled' REJECTED = 'rejected' response = '''{ "status":"fulfilled" }''' data = json.loads(response) status = data['status'] print(ResponseStatus(status))
Что, если статус не является одним из значений членов ResponseStatus? тогда вы получите ошибку. Например:
from enum import Enum import json class ResponseStatus(Enum): PENDING = 'pending' FULFILLED = 'fulfilled' REJECTED = 'rejected' response = '''{ "status":"ok" }''' data = json.loads(response) status = data['status'] print(ResponseStatus(status))
Ошибка:
ValueError: 'ok' is not a valid ResponseStatus
Чтобы перехватить исключение, вы можете использовать оператор try…except:
from enum import Enum import json class ResponseStatus(Enum): PENDING = 'pending' FULFILLED = 'fulfilled' REJECTED = 'rejected' response = '''{ "status":"ok" }''' data = json.loads(response) status = data['status'] try: if ResponseStatus(status) is ResponseStatus.FULFILLED: print('The request completed successfully') except ValueError as error: print(error)