zope.interface能定义类的__init__方法样式吗?

5 投票
3 回答
1753 浏览
提问于 2025-04-16 14:02

我有几个类似的类,它们都会用同样的代码来初始化,所以它们需要有相同的“构造函数签名”。(在动态的Python中真的有构造函数和签名吗?我有点跑题了。)

使用zope.interface,定义类的__init__参数的最佳方法是什么?

我会贴一些我用来实验zope.interface的代码,以便大家讨论:


from zope.interface import Interface, Attribute, implements, verify

class ITest(Interface):
    required_attribute = Attribute(
        """A required attribute for classes implementing this interface.""")
    def required_method():
        """A required method for classes implementing this interface."""

class Test(object):
    implements(ITest)
    required_attribute = None
    def required_method():
        pass

print verify.verifyObject(ITest, Test())
print verify.verifyClass(ITest, Test)

我不能在ITest中直接定义一个__init__函数,因为Python解释器会特别处理它——我觉得是这样?无论如何,这样似乎不太管用。那么,使用zope.interface定义“类构造函数”的最佳方法是什么呢?

3 个回答

0

你问的问题有点让人困惑。接口文件的作用是描述接口的内容,而不是提供某个具体的实现,随时可以被调用。你想要的是从一个共同的基类继承东西。但是,zope.interface 并不是用来做继承的。

1

不,__init__ 并没有被特殊处理:

from zope.interface import Interface, Attribute, implements, verify

class ITest(Interface):
    required_attribute = Attribute(
        """A required attribute for classes implementing this interface.""")
    def __init__(a,b):
        """Takes two parameters"""
    def required_method():
        """A required method for classes implementing this interface."""

class Test(object):
    implements(ITest)
    def __init__(self, a, b):
        self.required_attribute = a*b
    def required_method():
        return self.required_attribute

print verify.verifyClass(ITest, Test)
print verify.verifyObject(ITest, Test(2,3))

不过,我不太确定你具体在问什么。如果你想让多个类在 Python 中有相同的构造函数签名,唯一的方法就是这些类的构造函数签名真的要相同。:-) 不管你是通过继承来实现,还是每个类都有不同的 __init__,只要它们的签名一致就可以。

zope.interface 并不是用来定义方法的,而是用来声明签名的。因此,你可以定义一个具有特定签名的接口,包括 __init__,但这只是说“这个对象实现了 IMyFace 的签名”,而说一个类实现了一个接口并不会让这个类真的去实现这个接口。你仍然需要自己去实现它。

8

首先,提供实现接口这两个概念是有很大区别的。

简单来说,类是用来实现接口的,而这些类的实例则是用来提供这个接口的。可以把类想象成实例的蓝图,详细说明了它们的实现方式。

现在,接口描述的是实例所提供的实现,但__init__方法并不是实例的一部分!它实际上是类直接提供的接口的一部分(在Python中称为类方法)。如果你在接口中定义了一个__init__方法,那就意味着你的实例也有(提供)一个__init__方法(作为实例方法)。

所以,接口描述的是你能得到什么样的实例,而不是如何得到这些实例。

此外,接口不仅仅用来描述实例提供的功能。你还可以用接口来描述Python中的任何对象,包括模块和类。你需要使用directlyProvides方法来将接口分配给这些对象,因为你不会调用这些对象来创建实例。你也可以使用@provider()类装饰器,或者在类或模块声明中使用classProvidesmoduleProvides函数来达到同样的效果。

在这种情况下,你需要的是一个工厂定义;类就像工厂,当被调用时会产生一个实例,所以工厂接口必须提供一个__call__方法,以表明它们是可以被调用的。下面是一个设置了工厂接口的示例:

from zope import interface

class ITest(interface.Interface):
    required_attribute = interface.Attribute(
        """A required attribute for classes implementing this interface.""")
    def required_method():
        """A required method for classes implementing this interface."""

class ITestFactory(interface.Interface):
    """Creates objects providing the ITest interface"""
    def __call__(a, b):
        """Takes two parameters"""

@interface.implementer(ITest)
@interface.provider(ITestFactory)
class Test(object):
    def __init__(self, a, b):
        self.required_attribute = a*b

    def required_method():
        return self.required_attribute

zope.component包为你提供了一个方便的工厂类和接口,增加了getInterfaces方法,以及标题和描述,使得发现和检查变得更简单。然后你可以简单地继承IFactory接口,以更好地记录你的__init__参数:

from zope import component

class ITestFactory(component.interfaces.IFactory):
    """Creates objects providing the ITest interface"""
    def __call__(a, b):
        """Takes two parameters"""

testFactory = component.Factory(Test, 'ITest Factory', ITestFactory.__doc__)
interface.directlyProvides(testFactory, ITestFactory)

现在你可以将这个工厂注册为zope.component的一个工具,这样其他代码就可以找到所有的ITestFactory提供者。

我在这里使用了zope.interface.directlyProvides来标记工厂实例为你子类化的ITestFactory接口,因为zope.component.Factory实例通常只提供IFactory接口。

撰写回答