В данное руководство рассказывается, как работать с перечислениями (enum) в Python. Перечисление — это новый тип данных, введенный в Python 3.4.
Enum в Python
Перечисления — это наборы символических имен, связанных с уникальными константными значениями. Они используются для создания простых пользовательских типов данных, таких как времена года, недели, виды оружия в игре, планеты, оценки или дни. По соглашению имена перечислений начинаются с заглавной буквы и употребляются в единственном числе.
Модуль enum используется для создания перечислений в Python. Вы можете определить их с помощью ключевого слова class или с помощью функционального API.
Существуют специальные производные перечисления enum.IntEnum, enum.IntFlag и enum.Flag.
Простой пример использования enum в Python
Ниже приведен простой пример кода на Python, использующего перечисления.
#!/usr/bin/python3
from enum import Enum
class Weapon(Enum):
SWORD = 1
BOW = 2
DAGGER = 3
CLUB = 4
ranged_weapon = Weapon.BOW
print(ranged_weapon)
if ranged_weapon == Weapon.BOW:
print("It's a bow")
print(list(Weapon))
В примере у нас есть перечисление Weapon, которое имеет четыре различных значения: SWORD, BOW, DAGGER и CLUB. Чтобы получить доступ к одному из членов enum, мы должны указать название перечисления, за которым следует точка и имя интересующей нас символической константы.
class Weapon(Enum):
SWORD = 1
BOW = 2
DAGGER = 3
CLUB = 4
Перечисление Weapon создается нами с помощью ключевого слова class, то есть происходит наследование от базового класса enum.Enum. После этого мы явно задаем числа, соответствующие значениям перечисления.
ranged_weapon = Weapon.BOW
print(ranged_weapon)
Здесь символическая константа присваивается переменной и выводится на консоль.
if ranged_weapon == Weapon.BOW:
print("It's a bow")
Данный фрагмент демонстрирует использование Weapon.BOW в выражении if.
print(list(Weapon))
С помощью встроенной функции list мы получаем список всех возможных значений для перечисления Weapon.
Вывод:
Weapon.BOW
It's a bow
[, , , ]
Еще один пример использования enum в Python
В следующем примере представлена другая часть базовой функциональности перечислений в Python.
#!/usr/bin/python3
from enum import Enum
class Weapon(Enum):
SWORD = 1
BOW = 2
DAGGER = 3
CLUB = 4
weapon = Weapon.SWORD
print(weapon)
print(isinstance(weapon, Weapon))
print(type(weapon))
print(repr(weapon))
print(Weapon['SWORD'])
print(Weapon(1))
И снова мы имеем дело с enum Weapon, созданным с помощью класса.
print(weapon)
Здесь мы выводим человекочитаемое строковое представление одного из членов перечисления.
print(isinstance(weapon, Weapon))
С помощью метода isinstance мы проверяем, имеет ли переменная значение типа Weapon.
print(type(weapon))
Функция type выводит тип переменной.
print(repr(weapon))
Функция repr предоставляет дополнительную информацию о перечислении.
print(Weapon['SWORD'])
print(Weapon(1))
Доступ к символической константе можно получить как по ее имени, так и по значению (индексу).
Вывод:
Weapon.SWORD
True
Weapon.SWORD
Weapon.SWORD
Функциональное создание enum в Python
Перечисления Python также могут быть созданы с помощью функционального API.
from enum import Enum
Weapon = Enum('Weapon', 'SWORD BOW DAGGER CLUB', start=1)
weapon = Weapon.DAGGER
print(weapon)
if weapon == Weapon.DAGGER:
print("Dagger")
Есть несколько способов, как мы можем указать значения, используя функциональный API. В последующих примерах мы будем применять различные варианты их задания.
Weapon = Enum('Weapon', 'SWORD BOW DAGGER CLUB', start=1)
Здесь наименования символических констант задаются в строке, разделенные пробелами. Число, переданное в start, определяет начало нумерации значений для членов перечисления.
Вывод:
Weapon.DAGGER
Dagger
Итерирование enum в Python
Мы можем выполнять итерацию по перечислениям Python.
from enum import Enum
Weapon = Enum('Weapon', 'SWORD BOW DAGGER CLUB', start=10)
for weapon in Weapon:
print(weapon)
for weapon in Weapon:
print(weapon.name, weapon.value)
В этом примере мы создаем перечисление Weapon, где символьные константы задаются в виде списка строк.
for weapon in Weapon:
print(weapon)
В коде выше мы выполняем итерации по членам перечисления в цикле for.
for weapon in Weapon:
print(weapon.name, weapon.value)
Здесь мы выводим их имена и значения.
Вывод:
Weapon.SWORD
Weapon.BOW
Weapon.DAGGER
Weapon.CLUB
SWORD 10
BOW 11
DAGGER 12
CLUB 13
Автоматическое назначение имен для enum в Python
Значения символьных констант могут быть автоматически установлены с помощью функции auto().
#!/usr/bin/python3
from enum import Enum, auto
class Weapon(Enum):
SWORD = auto()
BOW = auto()
DAGGER = auto()
CLUB = auto()
for weapon in Weapon:
print(weapon.value)
В этом фрагменте мы создали перечисление Weapon, члены которого получают значения с помощью функции auto.
Вывод:
1
2
3
4
Уникальные значения enum в Python
Значения символьных констант могут быть принудительно уникальными с помощью декоратора @unique.
#!/usr/bin/python3
from enum import Enum, unique
@unique
class Weapon(Enum):
SWORD = 1
BOW = 2
DAGGER = 3
CLUB = 3
# CLUB = 4
for weapon in Weapon:
print(weapon)
Данный пример завершается с ошибкой ValueError: duplicate values found in : CLUB -> DAGGER, потому что члены CLUB и DAGGER имеют одинаковые значения. Если мы закомментируем декоратор @unique, пример выведет три члена; CLUB игнорируется.
Python enum __members__
Специальный атрибут members представляет собой упорядоченное отображение имен на символьные константы enum, доступное только для чтения.
#!/usr/bin/python3
from enum import Enum
Weapon = Enum('Weapon', [('SWORD', 1), ('BOW', 2),
('DAGGER', 3), ('CLUB', 4)])
for name, member in Weapon.__members__.items():
print(name, member)
В этом примере мы используем свойство members. Члены перечисления заданы списком кортежей с помощью функционального API.
Вывод:
SWORD Weapon.SWORD
BOW Weapon.BOW
DAGGER Weapon.DAGGER
CLUB Weapon.CLUB
enum.Flag
Enum.Flag — это базовый класс для создания пронумерованных констант, которые можно объединять с помощью побитовых операций без потери их принадлежности к Flag.
#!/usr/bin/python3
from enum import Flag, auto
class Permission(Flag):
READ = auto()
WRITE = auto()
EXECUTE = auto()
print(list(Permission))
print(Permission.READ | Permission.WRITE)
Пример выше показывает, как флаг может быть использован для проверки или установки разрешений.
Вывод:
[<Permission.READ: 1>, <Permission.WRITE: 2>, <Permission.EXECUTE: 4>]
Permission.WRITE|READ