Перечисления в Python

Эта публикация является как бы продолжением этой Константы в Python.

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

Что я подразумеваю под «групповыми» константами?

Это проще показать на примерах. В качестве самых ярких примеров подходят дни недели и месяцы.

Дни недели — это понедельник, вторник, среда и так далее. Месяцы — это январь, февраль, март,… Ну, вы поняли!

Программу, которая использует дни недели, было бы удобнее читать (и писать) не в стиле цифровых обозначений дней недели:

if today == 5:
    print("Ура! Сегодня маленький праздник!")

, а в стиле констант, обозначающих дни недели по-человечески, то есть словами. Вот так:

if today is dow.FRIDAY:
    print("Ура! Сегодня маленький праздник!")

(В тексте проги слово dow — это сокращение «Day Of Week», «день недели».)

В первом случае приходится гадать — какой это день недели прячется под цифрой 5?
А воскресенье — это какая цифра: 0 или 7? В этой проге нумерация осуществляется по-русски или по-американски?

Вы заметили, что в место операции сравнения «==» применяется инструкция «is»? В результате чего текст программы выглядит не «математическим», а «человеческим», то есть более естественным. А это означает, что потом читать и понимать эту программу будет значительно легче.

Что нам надо для такого стиля написания программ?

Нам понадобится модуль enum. В самом начале программы нужно добавить строку

from enum import Enum

, а далее определить наше перечисление констант. Например, для дней недели:

dow = Enum("DOW", "MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY SUNDAY")

Можно даже по-русски, если хотите!

, day.name
dow = Enum("DOW", "ПОНЕДЕЛЬНИК ВТОРНИК СРЕДА ЧЕТВЕРГ ПЯТНИЦА СУББОТА ВОСКРЕСЕНЬЕ")

Но я всё же не стал так смело применять русские обозначения. Во IntEnumвсяком случае не в коммерческих и не в публичных программах. Хотя люди что-то говорили, что идентификаторы в Питоне теперь Юникодовские (то есть можно писать названия переменных и функций хоть на еврейском, хоть на грузинском — хоть на каком!) Единственное неудобство состоит в том, что придётся чаще менять раскладку на клавиатуре (рус-англ) при наборе текста программы.

Пожалуй, более красиво будет, если названия дней недели сократить до двух-трёх букв. Ведь, благодаря префиксу dow их уже IntEnumнельзя будет спутать с чем-то другим.

Смотрите какая прелесть!

from enum import Enum
...
dow = Enum("DOW", "ПН ВТ СР ЧТ ПТ СБ ВС")
..., day.name

today = dow.ВТ  # Где-то в программе

...
if today is dow.ПТ:
    print("Ура! Сегодня маленький праздник!")
else:
    print("Эх! Я не доживу :(")

Я уверен, что пример для месяцев вы сами составите.

Однако, продолжаем прокачивать мозги!

А что делать, когда необходимо такие константы превратить в числа?

И в самом деле, сравнивать дни недели друг с другом с помощью инструкции «is» — это очень хорошо. Но ведь зачастую нужно обращаться к какому-либо списку (говоря на языке С/С++ — к массиву) по индексу. А индексы — это целые числа.

Не стоит отчаиваться! Дело в том, что полученное нами перечисление является перечислением классов. А у этих классов есть два свойства (два члена-данных): name и value.

name — это те константы, которые вы перечисляете через пробелы в определении перечисления dow. (Простите за тавтологию, но здесь без неё трудно обойтись!) В нашем перечислении dow семь констант: «ПН», «ВТ», «СР» и так далее.

value — это число, которое (автоматически) поставлено для соответствия константе. Это — целые числа: 1, 2, 3 и так далее. В IntEnumПитоне, в отличие от С/С++, перечисления начинаются с единицы. (На С/С++ перечисления начинаются с нуля.)

Так делается по умолчанию. Но если вам нужно начать перечисление с другого числа, то вы должны задать его явным образом с помощью параметра start.

dow = Enum("DOW", "ПН ВТ СР ЧТ ПТ СБ ВС", start="1000")

Сейчас константе dow.ПН будет соответствовать число 1000, константе dow.ВТ будет соответствовать число 1001, и так далее.

Таким образом, после этого определения мы можем написать такой код:

x = dow.ЧТ.value - 1000  # x = 3, так как dow.ЧТ.value = 1003
temperature = 36.6 + ARD[x]  # Определяем температуру больного
 

Здесь предполагается, что в списке ARD поправки к температуре. (ARD — это «acute respiratory disease», по русски ОРЗ, острое респираторное заболевание)

Вообще, если вы сомневаетесь в использовании созданного перечисления, то можете посмотреть на его содержимое:

>>> print(__members__)
OrderedDict([('ПН', <DOW.ПН: 1000>), ('ВТ', <DOW.ВТ: 1001>), ('СР', <DOW.СР: 1002>), ('ЧТ', <DOW.ЧТ: 1003>), ('ПТ', <DOW.ПТ: 1004>), ('СБ', <DOW.СБ: 1005>), ('ВС', <DOW.ВС: 1006>)])
>>> 

Не очень понятная каша, правда? Здесь я вывел содержимое перечисления, которое было задано в интерактивном режиме работы в среде Питон (а не в программе).

Однако, давайте вернёмся в программу и воспользуемся циклом.

for day in dow:
  print(day)

На экране должен появиться столбик констант:

DAW.ПН
DAW.ВТ
DAW.СР
DAW.ЧТ
DAW.ПТ
DAW.СБ
DAW.ВС

Теперь давайте ещё чуть-чуть усложним вывод:

for d in dow:
   print("{}: name = {}, value = {}".format(d, d.name, d.value))

У меня на экране появилось следующее:

DOW.ПН: name = ПН, value = 1000
DOW.ВТ: name = ВТ, value = 1001
DOW.СР: name = СР, value = 1002
DOW.ЧТ: name = ЧТ, value = 1003
DOW.ПТ: name = ПТ, value = 1004
DOW.СБ: name = СБ, value = 1005
DOW.ВС: name = ВС, value = 1006

Ну, наверно, уже хватит вас мучить.
Основное вы узнали — остальное, что я не сказал, добьете сами.

Без практики теория ничего не стоит. Пишите проги, получайте опыт, учите тех, кто идет вслед за вами. Только так мы сможем улучшить нашу жизнь, и когда мы все вместе. А всё остальное — от Лукавого. Проверено годами и не одной человеческой жизнью!

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s