Python, Архитектура компонентов Zope, Регистрация адаптера
В автономном приложении Python я использую пакеты zope.interface, zope.component для регистрации и доступа к адаптерам приложения. Я думал, что смогу использовать концепцию метакласса для регистрации адаптеров из метода init метакласса. Это "автоматизирует" процесс регистрации адаптера. Вы видите проблемы с этим подходом, например, с использованием атрибутов, которые пакет zope добавляет к классу? Спасибо заранее за ваш вклад.
from zope import component
from zope.interface import Interface, implements
class MetaclassAdapter(type):
def __init__(cls, clsname, bases, attrs):
super(MetaclassAdapter, cls).__init__(clsname, bases, attrs)
component.provideAdapter(cls, cls.__component_adapts__, cls.__implements_advice_data__[0][0])
class IDocument(Interface):
"""Document interface."""
def title():
pass
def author():
pass
def content():
pass
class IPrinter(Interface):
"""Printer interface."""
def write():
"""Print instance to ..."""
class Printer(object):
"""Adapt instances that provide IDocument interface to IPrinter.
Print document's attributes to stdout.
"""
__metaclass__ = MetaclassAdapter
implements(IPrinter)
component.adapts(IDocument)
def __init__(self, context):
"""Store adapted instance that provides IDocument."""
self.context = context
def write(self):
"""Serialize document."""
print 'author: ', self.context.author()
print 'title: ', self.context.title()
print 'content: ', self.context.content()
class TextDocument(object):
implements(IDocument)
def __init__(self, author, title, content):
self._author = author
self._title = title
self._content = content
def title(self):
return self._title
def author(self):
return self._author
def content(self):
return self._content
# Create instance of TextDocument and store / serialize it to...
IPrinter(TextDocument("Leo T.", "Short Stories", "Once upon a time...")).write()
2 ответа
То, что ты можешь, не означает, что ты должен.
Регистрация адаптера - это отдельная строка кода вне класса, так что я бы просто сделал это вместо того, чтобы скрыть поведение в метаклассе. Явное лучше, чем неявное.
Редактировать: идти с советом @ Тобу, не делай этого. Мой ответ ниже неправильный, но оставлен на месте для полноты картины. Это неверно, потому что перемешивание метакласса zope.interface.implements еще не обработало информацию об интерфейсе.
Я думаю, что подход, безусловно, вменяемый. Вам не нужно передавать предоставленный интерфейс или адаптированные спецификации для предоставления адаптера, метод регистрации определит их, если реализован только один интерфейс:
class MetaclassAdapter(type):
def __init__(cls, clsname, bases, attrs):
super(MetaclassAdapter, cls).__init__(clsname, bases, attrs)
component.provideAdapter(cls)
Если вы хотите поддерживать классы, которые реализуют более одного интерфейса (путем прямого объявления или через наследование), вам придется придумать семантику, чтобы определить, какой интерфейс будет выбран в качестве целевого интерфейса адаптера.
В этом случае просто передайте выбранный интерфейс для registerAdapter через параметр обеспечивает = ключевое слово. Я бы посоветовал вам использовать API интроспекции zope.interface (zope.interfaces.implementedBy), чтобы найти предоставленные интерфейсы, а не напрямую извлекать их из внутренних структур данных в классе.