简体   繁体   中英

Can zope.interface define how a class' __init__ method should look?

I have several similar classes which will all be initialised by the same code, and thus need to have the same "constructor signature." (Are there really constructors and signatures in the dynamic Python? I digress.)

What is the best way to define a classes __ init __ parameters using zope.interface?

I'll paste some code I've used for experimenting with zope.interface to facilitate discussion:


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)

I can't just define an __ init __ function in ITest, because it will be treated specially by the Python interpreter - I think? Whatever the case, it doesn't seem to work. So again, what is the best way to define a "class constructor" using a zope.interface?

First of all: there is a big difference between the concepts of providing and implementing an interface.

Basically, classes implement an interface, instances of those classes provide that interface. After all, classes are the blueprints for instances, detailing their implementations.

Now, an interface describes the implementation provided by instances, but the __init__ method is not a part of instances! It is part of the interface directly provided by classes instead (a classmethod in Python terminology). If you were to define an __init__ method in your interface, you are declaring that your instances have ( provide ) a __init__ method as well (as an instance method).

So interfaces describe what kind of instances you get, not how you get them.

Now, interfaces can be used for more than just describing what functionality an instance provides. You can also use interfaces for any kind object in Python, including modules and classes. You'll have to use the directlyProvides method to assign an interface to these, as you won't be calling these to create an instance. You can also use the @provider() class decorator, or the classProvides or moduleProvides functions from within a class or module declaration to get the same results.

What you want in this case is a factory definition; classes are factories that when called, produce an instance, so a factory interface must provide a __call__ method to indicate they are callable. Here is your example set up with a factory interface:

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

The zope.component package provides you with a convenience class and interface for factories , adding a getInterfaces method and a title and description to make discovery and introspection a little easier. You can then just subclass the IFactory interface to document your __init__ parameters a little better:

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)

You could now register that factory as a zope.component utility, for example, allowing other code to find all ITestFactory providers.

I used zope.interface.directlyProvides here to mark the factory instance with your subclassed ITestFactory interface, as zope.component.Factory instances normally only provide the IFactory interface.

No, __init__ is not handled differently:

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))

I'm not 100% sure what you are asking though. If you want to have the same constructor signature on several classes in Python, the only way to do that is to actually have the same constructor signature on these classes. :-) If you do this by subclassing or by having different __init__ for each class doesn't matter as long as they have the same signature.

zope.interface is not about defining methods, but declaring signatures. You can therefore define an interface that has a specific signature, also on the __init__ , but this is just saying "This object implements the signature IMyFace", but saying that a class implements an interface will not actually make the class implement the interface. You still need to implement it.

Does not make much sense what you are asking. The interface file is supposed to keep the interface description but not any specific implementation to be called from some where at any point. What you what is to inherit. from a common base class. zope.interface is NOT about inheritance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM