3

在一个独立的 python 应用程序中,我使用zope.interfacezope.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()
4

2 回答 2

3

仅仅因为你可以,并不意味着你应该。

注册适配器是类外的一行代码,所以我会这样做,而不是将行为隐藏在元类中。显式优于隐式。

于 2011-02-22T23:42:54.450 回答
1

编辑:遵循@Tobu 的建议,不要这样做。我在下面的回答是不正确的,但为了完整起见保留在原地。这是不正确的,因为 zope.interface.implements 元类 shuffle 尚未处理接口信息。

我认为这种方法当然是理智的。您不需要将提供的接口或适配的规范传递给providerAdapter,只要只实现一个接口,注册方法就会计算出来:

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

如果您想支持实现多个接口的类(通过直接声明或通过继承),则必须提出语义来确定选择哪个接口作为适配器目标接口。

在这种情况下,只需通过提供=关键字参数将所选接口提供给 registerAdapter。我建议您使用 zope.interface 自省 API (zope.interfaces.implementedBy) 来查找提供的接口,而不是直接从类的内部数据结构中获取它们。

于 2011-02-22T23:16:56.153 回答