У меня есть несколько классов, которые сохраняются в ZODB. Все классы должны иметь общие функции индексации, но также все они определяют множество свойств. Свойства определяются на уровне класса с дескрипторами, чтобы иметь возможность перехватывать запись в них для проверки и проверки дубликатов в БД. Для этого у каждого класса есть список автоматически поддерживаемых свойств, _properties
. Они также содержат _indices
и некоторые другие функции, которые я не хочу копировать отдельно для каждого класса Element (около 10).
Рассмотрим следующий код:
class BaseElement(object):
_properties = None
class ElementFlavour1(BaseElement):
_properties = 'a', 'b', 'c'
....
class ElementFlavourN(BaseElement):
_properties = 'e', 'f', 'g'
for item in locals():
if issubclass(item, BaseElement):
item._v_properties_set = set(item._properties) if item._properties else set()
Итак, он в основном делает то, что должен: мне нужно линейно перебирать _properties
, но я также хочу выполнять быстрый поиск, если в классе присутствует какое-либо свойство. Тем не менее, я не хочу повторяться и явно указывать этот набор для каждого отдельного варианта BaseElement
.
Текущее решение работает, но я считаю его уродливым приемом и хотел бы от него избавиться. Например. подклассы BaseElement
в других модулях не получат правильной настройки своих свойств. Игра с __new__
также кажется неправильным, поскольку он перехватывает не конструкцию класса, а создание экземпляра. Итак, как это сделать правильно?
P.S. Я знаю об OrderedDict, но это не то, что я ищу. Я хотел бы аккуратно подключиться к процессу создания класса и добавить туда произвольную функциональность.
1 ответ
Вы можете сделать это с метаклассом:
class BaseType(type):
def __init__(cls, name, bases, clsdict):
super(BaseType, cls).__init__(name, bases, clsdict)
setattr(cls,'_v_properties_set',
set(cls._properties) if cls._properties else set())
class BaseElement(object):
__metaclass__ = BaseType
_properties = None
class ElementFlavour1(BaseElement):
_properties = 'a', 'b', 'c'
class ElementFlavourN(BaseElement):
_properties = 'e', 'f', 'g'
print(ElementFlavourN._v_properties_set)
# set(['e', 'g', 'f'])
Вы также можете сделать это с помощью декоратора класса, но тогда вам придется декорировать каждый подкласс BaseElement
индивидуально. Метакласс наследуется, поэтому вам нужно определить его только один раз.
Похожие вопросы
Связанные вопросы
Новые вопросы
python
Python — это мультипарадигмальный многоцелевой язык программирования с динамической типизацией. Он предназначен для быстрого изучения, понимания и использования, а также обеспечивает чистый и унифицированный синтаксис. Обратите внимание, что Python 2 официально не поддерживается с 01.01.2020. Если у вас есть вопросы о версии Python, добавьте тег [python-2.7] или [python-3.x]. При использовании варианта Python (например, Jython, PyPy) или библиотеки (например, Pandas, NumPy) укажите это в тегах.