zope.interface能定义类的__init__方法样式吗?
我有几个类似的类,它们都会用同样的代码来初始化,所以它们需要有相同的“构造函数签名”。(在动态的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 个回答
你问的问题有点让人困惑。接口文件的作用是描述接口的内容,而不是提供某个具体的实现,随时可以被调用。你想要的是从一个共同的基类继承东西。但是,zope.interface 并不是用来做继承的。
不,__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 的签名”,而说一个类实现了一个接口并不会让这个类真的去实现这个接口。你仍然需要自己去实现它。
首先,提供和实现接口这两个概念是有很大区别的。
简单来说,类是用来实现接口的,而这些类的实例则是用来提供这个接口的。可以把类想象成实例的蓝图,详细说明了它们的实现方式。
现在,接口描述的是实例所提供的实现,但__init__
方法并不是实例的一部分!它实际上是类直接提供的接口的一部分(在Python中称为类方法)。如果你在接口中定义了一个__init__
方法,那就意味着你的实例也有(提供)一个__init__
方法(作为实例方法)。
所以,接口描述的是你能得到什么样的实例,而不是如何得到这些实例。
此外,接口不仅仅用来描述实例提供的功能。你还可以用接口来描述Python中的任何对象,包括模块和类。你需要使用directlyProvides
方法来将接口分配给这些对象,因为你不会调用这些对象来创建实例。你也可以使用@provider()
类装饰器,或者在类或模块声明中使用classProvides
或moduleProvides
函数来达到同样的效果。
在这种情况下,你需要的是一个工厂定义;类就像工厂,当被调用时会产生一个实例,所以工厂接口必须提供一个__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
接口。