我有几个类似的类,它们都将由相同的代码初始化,因此需要具有相同的“构造函数签名”。 (在动态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定义“类构造函数”的最佳方法是什么?
答案 0 :(得分:8)
首先:提供和实施接口的概念之间存在很大差异。
基本上,类实现接口,这些类的实例提供该接口。毕竟,类是实例的蓝图,详细说明了它们的实现。
现在,接口描述了实例提供的实现,但__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
包为您提供了便利class and interface for factories,添加了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
接口。
答案 1 :(得分:2)
不,__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))
我不是100%肯定你在问什么。如果你想在Python中的几个类上使用相同的构造函数签名,唯一的方法是在这些类上实际具有相同的构造函数签名。 :-)如果你通过子类化或通过对每个类使用不同的__init__
这样做,只要它们具有相同的签名就无关紧要。
zope.interface不是关于定义方法,而是声明签名。因此,您可以在__init__
上定义具有特定签名的接口,但这只是说“此对象实现了签名IMyFace”,但是说类实现接口实际上不会使类实现界面。你仍然需要实现它。
答案 2 :(得分:0)
你的要求没有多大意义。接口文件应该保留接口描述,但不能在任何时候从某些地方调用任何特定的实现。你要做什么才能继承。来自一个共同的基类。 zope.interface不是关于继承。