Рубрики
Без рубрики

enum – тип перечисления

Автор оригинала: Doug Hellmann.

Модуль ENUM определяет тип перечисления с итерацией и возможностями сравнения. Его можно использовать для создания четко определенных символов для значений, а не используя литеральные целые числа или строки.

Создание перечислений

Новое перечисление определяется с помощью синтаксиса Code> Code с помощью подкласса Enum и добавление атрибутов классов, описывающих значения.

enum_create.py

import enum


class BugStatus(enum.Enum):

    new  7
    incomplete  6
    invalid  5
    wont_fix  4
    in_progress  3
    fix_committed  2
    fix_released  1


print('\nMember name: {}'.format(BugStatus.wont_fix.name))
print('Member value: {}'.format(BugStatus.wont_fix.value))

Члены ENUM преобразуются в экземпляры, так как класс анализируется. Каждый экземпляр имеет имя <код> свойство, соответствующее имени участника и значение , соответствующее значению, назначенному имени в определении класса.

$ python3 enum_create.py


Member name: wont_fix
Member value: 4

Итерация

Итализация по поводу Enum класса производит отдельные члены перечисления.

enum_iterate.py

import enum


class BugStatus(enum.Enum):

    new  7
    incomplete  6
    invalid  5
    wont_fix  4
    in_progress  3
    fix_committed  2
    fix_released  1


for status in BugStatus:
    print('{:15} = {}'.format(status.name, status.value))

Участники производятся в том порядке, в котором они объявлены в определении класса. Имена и значения не используются для их сортировки.

$ python3 enum_iterate.py

new             = 7
incomplete      = 6
invalid         = 5
wont_fix        = 4
in_progress     = 3
fix_committed   = 2
fix_released    = 1

Сравнение enums.

Потому что члены перечисления не упорядочены, они поддерживают только сравнение личности и равенством.

enum_comparison.py

import enum


class BugStatus(enum.Enum):

    new  7
    incomplete  6
    invalid  5
    wont_fix  4
    in_progress  3
    fix_committed  2
    fix_released  1


actual_state  BugStatus.wont_fix
desired_state  BugStatus.fix_released

print('Equality:',
      actual_state  desired_state,
      actual_state  BugStatus.wont_fix)
print('Identity:',
      actual_state is desired_state,
      actual_state is BugStatus.wont_fix)
print('Ordered by value:')
try:
    print('\n'.join('  ' + s.name for s in sorted(BugStatus)))
except TypeError as err:
    print('  Cannot sort: {}'.format(err))

Операторы большего и менее чем сравнение повышают <код> ImporeError исключения.

$ python3 enum_comparison.py

Equality: False True
Identity: False True
Ordered by value:
  Cannot sort: '<' not supported between instances of 'BugStatus
' and 'BugStatus'

Используйте класс INTENUM для перечислений, в которых члены должны вести себя больше похожи на цифры, например, для поддержки сравнений.

enum_intenum.py

import enum


class BugStatus(enum.IntEnum):

    new  7
    incomplete  6
    invalid  5
    wont_fix  4
    in_progress  3
    fix_committed  2
    fix_released  1


print('Ordered by value:')
print('\n'.join('  ' + s.name for s in sorted(BugStatus)))
$ python3 enum_intenum.py

Ordered by value:
  fix_released
  fix_committed
  in_progress
  wont_fix
  invalid
  incomplete
  new

Уникальные значения перечисления

Участники Enum с одинаковым значением отслеживаются как ссылки на псевдоним к тому же объекту-члену. Псевдонимы не вызывают повторных значений в итераторе для ENUM .

enum_aliases.py

import enum


class BugStatus(enum.Enum):

    new  7
    incomplete  6
    invalid  5
    wont_fix  4
    in_progress  3
    fix_committed  2
    fix_released  1

    by_design  4
    closed  1


for status in BugStatus:
    print('{:15} = {}'.format(status.name, status.value))

print('\nSame: by_design is wont_fix: ',
      BugStatus.by_design is BugStatus.wont_fix)
print('Same: closed is fix_released: ',
      BugStatus.closed is BugStatus.fix_released)

Поскольку <код> by_design и <код> закрыты – псевдонимы для других участников, они не отображаются отдельно на выходе при итерации по адресу <код> enum . Каноническое имя для члена – это имя, прикрепленное к значению.

$ python3 enum_aliases.py

new             = 7
incomplete      = 6
invalid         = 5
wont_fix        = 4
in_progress     = 3
fix_committed   = 2
fix_released    = 1

Same: by_design is wont_fix:  True
Same: closed is fix_released:  True

Чтобы все участники имели уникальные значения, добавьте <код> @Unique декоратор на <код> enum .

enum_unique_enforce.py

import enum


@enum.unique
class BugStatus(enum.Enum):

    new  7
    incomplete  6
    invalid  5
    wont_fix  4
    in_progress  3
    fix_committed  2
    fix_released  1

    # This will trigger an error with unique applied.
    by_design  4
    closed  1

Участники с повторяющимися значениями вызывают ValueError , когда <код> enum интерпретируется.

$ python3 enum_unique_enforce.py

Traceback (most recent call last):
  File "enum_unique_enforce.py", line 11, in 
    class BugStatus(enum.Enum):
  File ".../lib/python3.7/enum.py", line 848, in unique
    (enumeration, alias_details))
ValueError: duplicate values found in :
by_design -> wont_fix, closed -> fix_released

Создание перечисления программно

В некоторых случаях удобнее создавать перечисление программно, а не жестко кодирующим их в определении класса. Для этих ситуаций Enum также поддерживает передачу имен элементов и значений классу конструктора.

enum_programmatic_create.py

import enum


BugStatus  enum.Enum(
    value'BugStatus',
    names('fix_released fix_committed in_progress '
           'wont_fix invalid incomplete new'),
)

print('Member: {}'.format(BugStatus.new))

print('\nAll members:')
for status in BugStatus:
    print('{:15} = {}'.format(status.name, status.value))

Объект – это имя перечисления, которое используется для создания представления членов. Имена Argument перечислены члены перечисления. Когда пропущена одна строка, она разделена на пробел и запятые, и полученные токены используются в качестве имени для членов, которые автоматически назначаются значения, начиная с 1 .

$ python3 enum_programmatic_create.py

Member: BugStatus.new

All members:
fix_released    = 1
fix_committed   = 2
in_progress     = 3
wont_fix        = 4
invalid         = 5
incomplete      = 6
new             = 7

Для более контроля над значениями, связанными с элементами, может быть заменена последовательностью двухфункциональных кортежей или имена сопоставления словаря к значениям.

enum_programmatic_mapping.py

import enum


BugStatus  enum.Enum(
    value'BugStatus',
    names[
        ('new', 7),
        ('incomplete', 6),
        ('invalid', 5),
        ('wont_fix', 4),
        ('in_progress', 3),
        ('fix_committed', 2),
        ('fix_released', 1),
    ],
)

print('All members:')
for status in BugStatus:
    print('{:15} = {}'.format(status.name, status.value))

В этом примере список кортежей из двух частей приведен вместо одной строки, содержащей только имена элементов. Это позволяет восстановить реконструкцию BUGSTATUS перечисления с членами в том же порядке, что и версия, определенная в Enum_Crate.py .

$ python3 enum_programmatic_mapping.py

All members:
new             = 7
incomplete      = 6
invalid         = 5
wont_fix        = 4
in_progress     = 3
fix_committed   = 2
fix_released    = 1

Значения не целочисленных членов

Значения элементов элементов не ограничены целыми числами. На самом деле любой тип объекта может быть связан с участником. Если значение представляет собой кортеж, члены передаются как отдельные аргументы <код> __ init __ () .

enum_tuple_values.py

import enum


class BugStatus(enum.Enum):

    new  (7, ['incomplete',
               'invalid',
               'wont_fix',
               'in_progress'])
    incomplete  (6, ['new', 'wont_fix'])
    invalid  (5, ['new'])
    wont_fix  (4, ['new'])
    in_progress  (3, ['new', 'fix_committed'])
    fix_committed  (2, ['in_progress', 'fix_released'])
    fix_released  (1, ['new'])

    def __init__(self, num, transitions):
        self.num  num
        self.transitions  transitions

    def can_transition(self, new_state):
        return new_state.name in self.transitions


print('Name:', BugStatus.in_progress)
print('Value:', BugStatus.in_progress.value)
print('Custom attribute:', BugStatus.in_progress.transitions)
print('Using attribute:',
      BugStatus.in_progress.can_transition(BugStatus.new))

В этом примере каждое значение элемента представляет собой кортеж, содержащий числовой идентификатор (например, может храниться в базе данных), так и в списке действительных переходов от текущего состояния.

$ python3 enum_tuple_values.py

Name: BugStatus.in_progress
Value: (3, ['new', 'fix_committed'])
Custom attribute: ['new', 'fix_committed']
Using attribute: True

Для более сложных случаев кортежи могут стать громоздкими. Поскольку значения элементов могут быть любым типом объекта, словари могут использоваться для случаев, когда есть много отдельных атрибутов для отслеживания для каждого значения Enum. Комплексные значения передаются непосредственно к <код> __ init __ () как единственный аргумент, отличный от <код> Self .

enum_complex_values.py

import enum


class BugStatus(enum.Enum):

    new  {
        'num': 7,
        'transitions': [
            'incomplete',
            'invalid',
            'wont_fix',
            'in_progress',
        ],
    }
    incomplete  {
        'num': 6,
        'transitions': ['new', 'wont_fix'],
    }
    invalid  {
        'num': 5,
        'transitions': ['new'],
    }
    wont_fix  {
        'num': 4,
        'transitions': ['new'],
    }
    in_progress  {
        'num': 3,
        'transitions': ['new', 'fix_committed'],
    }
    fix_committed  {
        'num': 2,
        'transitions': ['in_progress', 'fix_released'],
    }
    fix_released  {
        'num': 1,
        'transitions': ['new'],
    }

    def __init__(self, vals):
        self.num  vals['num']
        self.transitions  vals['transitions']

    def can_transition(self, new_state):
        return new_state.name in self.transitions


print('Name:', BugStatus.in_progress)
print('Value:', BugStatus.in_progress.value)
print('Custom attribute:', BugStatus.in_progress.transitions)
print('Using attribute:',
      BugStatus.in_progress.can_transition(BugStatus.new))

В этом примере выражается те же данные, что и предыдущий пример, используя словари, скорее

$ python3 enum_complex_values.py

Name: BugStatus.in_progress
Value: {'num': 3, 'transitions': ['new', 'fix_committed']}
Custom attribute: ['new', 'fix_committed']
Using attribute: True

Смотрите также