Python, Архитектура компонентов Zope, Регистрация адаптера - PullRequest
3 голосов
/ 22 февраля 2011

В автономном приложении 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 ]

3 голосов
/ 23 февраля 2011

То, что вы можете, не значит, что вы должны.

Регистрация адаптера - это отдельная строка кода вне класса, так что я бы просто сделал это вместо того, чтобы скрыть поведение в метаклассе. Явное лучше, чем неявное.

1 голос
/ 23 февраля 2011

Редактировать: следуйте совету @ Тобу, не делай этого.Мой ответ ниже неправильный, но оставлен на месте для полноты картины.Это неверно, потому что перемешивание метакласса zope.interface.implements еще не обработало информацию об интерфейсе.

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

class MetaclassAdapter(type):
    def __init__(cls, clsname, bases, attrs):
        super(MetaclassAdapter, cls).__init__(clsname, bases, attrs)
        component.provideAdapter(cls)

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

В этом случае просто передайте выбранный интерфейс для registerAdapter с помощью параметра provide = keyword.Я бы посоветовал вам использовать API интроспекции zope.interface (zope.interfaces.implementedBy), чтобы найти предоставленные интерфейсы, а не напрямую извлекать их из внутренних структур данных в классе.

...