Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Ещё одна реализация Enums для Python

Anna | 15.06.2014 | нет комментариев
В прошлом году сообщество Python наконец-то договорилось о реализации перечислений. Было разработано соответствующее предложение PEP 435, его реализация теснее есть в python 3.4.

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

На нынешний момент эксперименты завершены, библиотека отлично показала себя в моих планах, следственно я решил поделиться ей с сообществом.

В большинстве случаев, когда мы описываем отношение вида <имя, значение>, у нас имеется много информации, которую желанно привязать к имени: вспомогательный текст для пользовательского интерфейса, связи с родными перечислениями, ссылки на другие объекты либо функции. Доводится городить добавочные конструкции данных, что не есть отлично — лишние сущности как-никак.

Следственно, вдохновившись реляционной моделью данных, я решил отказаться от реализации перечислений в виде бинарных отношений и расширить их до полновесной таблицы.

Заодно добавил:

  • наследование;
  • несколько вспомогательных способов и проверок;
  • построение индексов по каждому столбцам таблицы;
  • образование обратных ссылок в связанных друг с ином отношениях;

В результате получилось вот такая вещь (примеры решил не дробить, Дабы не увеличивать и так длинное «полотно»):

########################
# Базовое применение
########################

from rels import Column, Relation

# Enum и EnumWithText теснее объявлены в библиотеке
# и доступны как rels.Enum и rels.EnumWithText
# здесь их объявления привидены для облегчения понимания

class Enum(Relation):             # объявляем абстраткное перечисление
    name = Column(primary=True)   # столбец с именами
    value = Column(external=True) # столбец со значениями

# наследование — добавляем добавочный столбец для какого-нибудь текста
#                скажем, для применения в пользовательском интерфейсе
class EnumWithText(Enum):
    text = Column()

class SOME_CONSTANTS(Enum):       # объявляем определенное перечисление
    records = ( ('NAME_1', 1),    # и указываем данные для него
                ('NAME_2', 2))

class SOME_CONSTANTS_WITH_TEXT(EnumWithText): # ещё одно определенное перечисление
    records = ( ('NAME_1', 1, 'constant 1'),
                ('NAME_2', 2, 'constant 2'))

# Трудимся с перечислениями

# доступ к данным
SOME_CONSTANTS.NAME_1.name == 'NAME_1'          # True
SOME_CONSTANTS.NAME_1.value == 1                # True

# приобретение элемента перечисления из «сырых» данных
SOME_CONSTANTS(1) == SOME_CONSTANTS.NAME_1      # True

# сопоставления
SOME_CONSTANTS.NAME_2 == SOME_CONSTANTS.NAME_2  # True
SOME_CONSTANTS.NAME_2 != SOME_CONSTANTS.NAME_1  # True

# сейчас для проверок не нужно везде тягать импорты перечисления
SOME_CONSTANTS.NAME_2.is_NAME_1                 # False
SOME_CONSTANTS.NAME_2.is_NAME_2                 # True

# всякий элемент перечисления — обособленный объект,
# следственно даже объекты с идентичными данными равны не будут
SOME_CONSTANTS.NAME_2 != SOME_CONSTANTS_WITH_TEXT.NAME_2  # True
SOME_CONSTANTS.NAME_1 != SOME_CONSTANTS_WITH_TEXT.NAME_1  # True

# наследование — добавляем новые элементы
class EXTENDED_CONSTANTS(SOME_CONSTANTS_WITH_TEXT):  # расширяем комплект данных в перечислении
    records = ( ('NAME_3', 3, 'constant 3'), )       # добавляем ещё одно значение

########################
# Индексы
########################

class ENUM(Relation):
    name = Column(primary=True)   # для этого столбца имя индекса будет .index_name
    value = Column(external=True) # для этого столбца имя индекса будет .index_value
    text = Column(unique=False, index_name='by_key') # указываем своё имя для индекса

    records = ( ('NAME_1', 0, 'key_1'),
                ('NAME_2', 1, 'key_2'),
                ('NAME_3', 2, 'key_2'), )

# если данные в столбце уникальны, значением в словаре будет элемент перечисления
ENUM.index_name # {'NAME_1': ENUM.NAME_1, 'NAME_2': ENUM.NAME_2,  'NAME_3': ENUM.NAME_3}

# если данные в столбце не уникальны, значением в словаре будет список элементов перечисления
ENUM.by_key     # {'key_1': [ENUM.NAME_1], 'key_2': [ENUM.NAME_2, ENUM.NAME_3]}

########################
# Обратные ссылки
########################

# объявляем отношение, на которое будем ссылаться
class DESTINATION_ENUM(Relation):
    name = Column(primary=True)
    val = Column()

    records = ( ('STATE_1', 'value_1'),
                ('STATE_2', 'value_2') )

# объявляем отношение, которое будет ссылаться
class SOURCE_ENUM(Relation):
    name = Column(primary=True)
    val = Column()
    rel = Column(related_name='rel_source')

    records = ( ('STATE_1', 'value_1', DESTINATION_ENUM.STATE_1),
                ('STATE_2', 'value_2', DESTINATION_ENUM.STATE_2) )

# проверяем работу ссылок
DESTINATION_ENUM.STATE_1.rel_source == SOURCE_ENUM.STATE_1 # True
DESTINATION_ENUM.STATE_2 == SOURCE_ENUM.STATE_2.rel        # True

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

Репозиторий и подробная документация на github

P.S. библиотека разрабатывалась в расчёте на Python 2.7, с третьим не проверялась.

Необходимы ли альтернативные реализации перечислений для Питона?

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Проголосовало 6 человек. Воздержалось 2 человека.

 Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB