summaryrefslogtreecommitdiff
path: root/docs/README.rst
diff options
context:
space:
mode:
authorTres Seaver <tseaver@palladion.com>2012-03-26 20:56:58 +0000
committerTres Seaver <tseaver@palladion.com>2012-03-26 20:56:58 +0000
commitbc4d8bc1569c9d4dc28c62272a5acbaebc04cdfe (patch)
tree605f4701a12fc03dc084e6115d6f07ef1a152029 /docs/README.rst
parent2fd652d0d095b79e2e6365b00c739f589bf631a5 (diff)
downloadzope-interface-bc4d8bc1569c9d4dc28c62272a5acbaebc04cdfe.tar.gz
Merge from LP branch.
Diffstat (limited to 'docs/README.rst')
-rw-r--r--docs/README.rst829
1 files changed, 829 insertions, 0 deletions
diff --git a/docs/README.rst b/docs/README.rst
new file mode 100644
index 0000000..253d1ed
--- /dev/null
+++ b/docs/README.rst
@@ -0,0 +1,829 @@
+==========
+Interfaces
+==========
+
+Interfaces are objects that specify (document) the external behavior
+of objects that "provide" them. An interface specifies behavior
+through:
+
+- Informal documentation in a doc string
+
+- Attribute definitions
+
+- Invariants, which are conditions that must hold for objects that
+ provide the interface
+
+Attribute definitions specify specific attributes. They define the
+attribute name and provide documentation and constraints of attribute
+values. Attribute definitions can take a number of forms, as we'll
+see below.
+
+Defining interfaces
+===================
+
+Interfaces are defined using Python class statements::
+
+ >>> import zope.interface
+ >>> class IFoo(zope.interface.Interface):
+ ... """Foo blah blah"""
+ ...
+ ... x = zope.interface.Attribute("""X blah blah""")
+ ...
+ ... def bar(q, r=None):
+ ... """bar blah blah"""
+
+In the example above, we've created an interface, `IFoo`. We
+subclassed `zope.interface.Interface`, which is an ancestor interface for
+all interfaces, much as `object` is an ancestor of all new-style
+classes [#create]_. The interface is not a class, it's an Interface,
+an instance of `InterfaceClass`::
+
+ >>> type(IFoo)
+ <class 'zope.interface.interface.InterfaceClass'>
+
+We can ask for the interface's documentation::
+
+ >>> IFoo.__doc__
+ 'Foo blah blah'
+
+and its name::
+
+ >>> IFoo.__name__
+ 'IFoo'
+
+and even its module::
+
+ >>> IFoo.__module__
+ '__main__'
+
+The interface defined two attributes:
+
+`x`
+ This is the simplest form of attribute definition. It has a name
+ and a doc string. It doesn't formally specify anything else.
+
+`bar`
+ This is a method. A method is defined via a function definition. A
+ method is simply an attribute constrained to be a callable with a
+ particular signature, as provided by the function definition.
+
+ Note that `bar` doesn't take a `self` argument. Interfaces document
+ how an object is *used*. When calling instance methods, you don't
+ pass a `self` argument, so a `self` argument isn't included in the
+ interface signature. The `self` argument in instance methods is
+ really an implementation detail of Python instances. Other objects,
+ besides instances can provide interfaces and their methods might not
+ be instance methods. For example, modules can provide interfaces and
+ their methods are usually just functions. Even instances can have
+ methods that are not instance methods.
+
+You can access the attributes defined by an interface using mapping
+syntax::
+
+ >>> x = IFoo['x']
+ >>> type(x)
+ <class 'zope.interface.interface.Attribute'>
+ >>> x.__name__
+ 'x'
+ >>> x.__doc__
+ 'X blah blah'
+
+ >>> IFoo.get('x').__name__
+ 'x'
+
+ >>> IFoo.get('y')
+
+You can use `in` to determine if an interface defines a name::
+
+ >>> 'x' in IFoo
+ True
+
+You can iterate over interfaces to get the names they define::
+
+ >>> names = list(IFoo)
+ >>> names.sort()
+ >>> names
+ ['bar', 'x']
+
+Remember that interfaces aren't classes. You can't access attribute
+definitions as attributes of interfaces::
+
+ >>> IFoo.x
+ Traceback (most recent call last):
+ File "<stdin>", line 1, in ?
+ AttributeError: 'InterfaceClass' object has no attribute 'x'
+
+Methods provide access to the method signature::
+
+ >>> bar = IFoo['bar']
+ >>> bar.getSignatureString()
+ '(q, r=None)'
+
+TODO
+ Methods really should have a better API. This is something that
+ needs to be improved.
+
+Declaring interfaces
+====================
+
+Having defined interfaces, we can *declare* that objects provide
+them. Before we describe the details, lets define some terms:
+
+*provide*
+ We say that objects *provide* interfaces. If an object provides an
+ interface, then the interface specifies the behavior of the
+ object. In other words, interfaces specify the behavior of the
+ objects that provide them.
+
+*implement*
+ We normally say that classes *implement* interfaces. If a class
+ implements an interface, then the instances of the class provide
+ the interface. Objects provide interfaces that their classes
+ implement [#factory]_. (Objects can provide interfaces directly,
+ in addition to what their classes implement.)
+
+ It is important to note that classes don't usually provide the
+ interfaces that they implement.
+
+ We can generalize this to factories. For any callable object we
+ can declare that it produces objects that provide some interfaces
+ by saying that the factory implements the interfaces.
+
+Now that we've defined these terms, we can talk about the API for
+declaring interfaces.
+
+Declaring implemented interfaces
+--------------------------------
+
+The most common way to declare interfaces is using the implements
+function in a class statement::
+
+ >>> class Foo:
+ ... zope.interface.implements(IFoo)
+ ...
+ ... def __init__(self, x=None):
+ ... self.x = x
+ ...
+ ... def bar(self, q, r=None):
+ ... return q, r, self.x
+ ...
+ ... def __repr__(self):
+ ... return "Foo(%s)" % self.x
+
+
+In this example, we declared that `Foo` implements `IFoo`. This means
+that instances of `Foo` provide `IFoo`. Having made this declaration,
+there are several ways we can introspect the declarations. First, we
+can ask an interface whether it is implemented by a class::
+
+ >>> IFoo.implementedBy(Foo)
+ True
+
+And we can ask whether an interface is provided by an object::
+
+ >>> foo = Foo()
+ >>> IFoo.providedBy(foo)
+ True
+
+Of course, `Foo` doesn't provide `IFoo`, it implements it::
+
+ >>> IFoo.providedBy(Foo)
+ False
+
+We can also ask what interfaces are implemented by an object::
+
+ >>> list(zope.interface.implementedBy(Foo))
+ [<InterfaceClass __main__.IFoo>]
+
+It's an error to ask for interfaces implemented by a non-callable
+object::
+
+ >>> IFoo.implementedBy(foo)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+ >>> list(zope.interface.implementedBy(foo))
+ Traceback (most recent call last):
+ ...
+ TypeError: ('ImplementedBy called for non-factory', Foo(None))
+
+Similarly, we can ask what interfaces are provided by an object::
+
+ >>> list(zope.interface.providedBy(foo))
+ [<InterfaceClass __main__.IFoo>]
+ >>> list(zope.interface.providedBy(Foo))
+ []
+
+We can declare interfaces implemented by other factories (besides
+classes). We do this using a Python-2.4-style decorator named
+`implementer`. In versions of Python before 2.4, this looks like::
+
+ >>> def yfoo(y):
+ ... foo = Foo()
+ ... foo.y = y
+ ... return foo
+ >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+ >>> list(zope.interface.implementedBy(yfoo))
+ [<InterfaceClass __main__.IFoo>]
+
+Note that the implementer decorator may modify it's argument. Callers
+should not assume that a new object is created.
+
+Using implementer also works on callable objects. This is used by
+zope.formlib, as an example.
+
+ >>> class yfactory:
+ ... def __call__(self, y):
+ ... foo = Foo()
+ ... foo.y = y
+ ... return foo
+ >>> yfoo = yfactory()
+ >>> yfoo = zope.interface.implementer(IFoo)(yfoo)
+
+ >>> list(zope.interface.implementedBy(yfoo))
+ [<InterfaceClass __main__.IFoo>]
+
+XXX: Double check and update these version numbers:
+
+In zope.interface 3.5.2 and lower, the implementer decorator can not
+be used for classes, but in 3.6.0 and higher it can:
+
+ >>> Foo = zope.interface.implementer(IFoo)(Foo)
+ >>> list(zope.interface.providedBy(Foo()))
+ [<InterfaceClass __main__.IFoo>]
+
+Note that class decorators using the @implementer(IFoo) syntax are only
+supported in Python 2.6 and later.
+
+
+Declaring provided interfaces
+-----------------------------
+
+We can declare interfaces directly provided by objects. Suppose that
+we want to document what the `__init__` method of the `Foo` class
+does. It's not *really* part of `IFoo`. You wouldn't normally call
+the `__init__` method on Foo instances. Rather, the `__init__` method
+is part of the `Foo`'s `__call__` method::
+
+ >>> class IFooFactory(zope.interface.Interface):
+ ... """Create foos"""
+ ...
+ ... def __call__(x=None):
+ ... """Create a foo
+ ...
+ ... The argument provides the initial value for x ...
+ ... """
+
+It's the class that provides this interface, so we declare the
+interface on the class::
+
+ >>> zope.interface.directlyProvides(Foo, IFooFactory)
+
+And then, we'll see that Foo provides some interfaces::
+
+ >>> list(zope.interface.providedBy(Foo))
+ [<InterfaceClass __main__.IFooFactory>]
+ >>> IFooFactory.providedBy(Foo)
+ True
+
+Declaring class interfaces is common enough that there's a special
+declaration function for it, `classProvides`, that allows the
+declaration from within a class statement::
+
+ >>> class Foo2:
+ ... zope.interface.implements(IFoo)
+ ... zope.interface.classProvides(IFooFactory)
+ ...
+ ... def __init__(self, x=None):
+ ... self.x = x
+ ...
+ ... def bar(self, q, r=None):
+ ... return q, r, self.x
+ ...
+ ... def __repr__(self):
+ ... return "Foo(%s)" % self.x
+
+ >>> list(zope.interface.providedBy(Foo2))
+ [<InterfaceClass __main__.IFooFactory>]
+ >>> IFooFactory.providedBy(Foo2)
+ True
+
+There's a similar function, `moduleProvides`, that supports interface
+declarations from within module definitions. For example, see the use
+of `moduleProvides` call in `zope.interface.__init__`, which declares that
+the package `zope.interface` provides `IInterfaceDeclaration`.
+
+Sometimes, we want to declare interfaces on instances, even though
+those instances get interfaces from their classes. Suppose we create
+a new interface, `ISpecial`::
+
+ >>> class ISpecial(zope.interface.Interface):
+ ... reason = zope.interface.Attribute("Reason why we're special")
+ ... def brag():
+ ... "Brag about being special"
+
+We can make an existing foo instance special by providing `reason`
+and `brag` attributes::
+
+ >>> foo.reason = 'I just am'
+ >>> def brag():
+ ... return "I'm special!"
+ >>> foo.brag = brag
+ >>> foo.reason
+ 'I just am'
+ >>> foo.brag()
+ "I'm special!"
+
+and by declaring the interface::
+
+ >>> zope.interface.directlyProvides(foo, ISpecial)
+
+then the new interface is included in the provided interfaces::
+
+ >>> ISpecial.providedBy(foo)
+ True
+ >>> list(zope.interface.providedBy(foo))
+ [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+We can find out what interfaces are directly provided by an object::
+
+ >>> list(zope.interface.directlyProvidedBy(foo))
+ [<InterfaceClass __main__.ISpecial>]
+
+ >>> newfoo = Foo()
+ >>> list(zope.interface.directlyProvidedBy(newfoo))
+ []
+
+Inherited declarations
+----------------------
+
+Normally, declarations are inherited::
+
+ >>> class SpecialFoo(Foo):
+ ... zope.interface.implements(ISpecial)
+ ... reason = 'I just am'
+ ... def brag(self):
+ ... return "I'm special because %s" % self.reason
+
+ >>> list(zope.interface.implementedBy(SpecialFoo))
+ [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+ >>> list(zope.interface.providedBy(SpecialFoo()))
+ [<InterfaceClass __main__.ISpecial>, <InterfaceClass __main__.IFoo>]
+
+Sometimes, you don't want to inherit declarations. In that case, you
+can use `implementsOnly`, instead of `implements`::
+
+ >>> class Special(Foo):
+ ... zope.interface.implementsOnly(ISpecial)
+ ... reason = 'I just am'
+ ... def brag(self):
+ ... return "I'm special because %s" % self.reason
+
+ >>> list(zope.interface.implementedBy(Special))
+ [<InterfaceClass __main__.ISpecial>]
+
+ >>> list(zope.interface.providedBy(Special()))
+ [<InterfaceClass __main__.ISpecial>]
+
+External declarations
+---------------------
+
+Normally, we make implementation declarations as part of a class
+definition. Sometimes, we may want to make declarations from outside
+the class definition. For example, we might want to declare interfaces
+for classes that we didn't write. The function `classImplements` can
+be used for this purpose::
+
+ >>> class C:
+ ... pass
+
+ >>> zope.interface.classImplements(C, IFoo)
+ >>> list(zope.interface.implementedBy(C))
+ [<InterfaceClass __main__.IFoo>]
+
+We can use `classImplementsOnly` to exclude inherited interfaces::
+
+ >>> class C(Foo):
+ ... pass
+
+ >>> zope.interface.classImplementsOnly(C, ISpecial)
+ >>> list(zope.interface.implementedBy(C))
+ [<InterfaceClass __main__.ISpecial>]
+
+
+
+Declaration Objects
+-------------------
+
+When we declare interfaces, we create *declaration* objects. When we
+query declarations, declaration objects are returned::
+
+ >>> type(zope.interface.implementedBy(Special))
+ <class 'zope.interface.declarations.Implements'>
+
+Declaration objects and interface objects are similar in many ways. In
+fact, they share a common base class. The important thing to realize
+about them is that they can be used where interfaces are expected in
+declarations. Here's a silly example::
+
+ >>> class Special2(Foo):
+ ... zope.interface.implementsOnly(
+ ... zope.interface.implementedBy(Foo),
+ ... ISpecial,
+ ... )
+ ... reason = 'I just am'
+ ... def brag(self):
+ ... return "I'm special because %s" % self.reason
+
+The declaration here is almost the same as
+``zope.interface.implements(ISpecial)``, except that the order of
+interfaces in the resulting declaration is different::
+
+ >>> list(zope.interface.implementedBy(Special2))
+ [<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.ISpecial>]
+
+
+Interface Inheritance
+=====================
+
+Interfaces can extend other interfaces. They do this simply by listing
+the other interfaces as base interfaces::
+
+ >>> class IBlat(zope.interface.Interface):
+ ... """Blat blah blah"""
+ ...
+ ... y = zope.interface.Attribute("y blah blah")
+ ... def eek():
+ ... """eek blah blah"""
+
+ >>> IBlat.__bases__
+ (<InterfaceClass zope.interface.Interface>,)
+
+ >>> class IBaz(IFoo, IBlat):
+ ... """Baz blah"""
+ ... def eek(a=1):
+ ... """eek in baz blah"""
+ ...
+
+ >>> IBaz.__bases__
+ (<InterfaceClass __main__.IFoo>, <InterfaceClass __main__.IBlat>)
+
+ >>> names = list(IBaz)
+ >>> names.sort()
+ >>> names
+ ['bar', 'eek', 'x', 'y']
+
+Note that `IBaz` overrides eek::
+
+ >>> IBlat['eek'].__doc__
+ 'eek blah blah'
+ >>> IBaz['eek'].__doc__
+ 'eek in baz blah'
+
+We were careful to override eek in a compatible way. When extending
+an interface, the extending interface should be compatible [#compat]_
+with the extended interfaces.
+
+We can ask whether one interface extends another::
+
+ >>> IBaz.extends(IFoo)
+ True
+ >>> IBlat.extends(IFoo)
+ False
+
+Note that interfaces don't extend themselves::
+
+ >>> IBaz.extends(IBaz)
+ False
+
+Sometimes we wish they did, but we can, instead use `isOrExtends`::
+
+ >>> IBaz.isOrExtends(IBaz)
+ True
+ >>> IBaz.isOrExtends(IFoo)
+ True
+ >>> IFoo.isOrExtends(IBaz)
+ False
+
+When we iterate over an interface, we get all of the names it defines,
+including names defined by base interfaces. Sometimes, we want *just*
+the names defined by the interface directly. We bane use the `names`
+method for that::
+
+ >>> list(IBaz.names())
+ ['eek']
+
+Inheritance of attribute specifications
+---------------------------------------
+
+An interface may override attribute definitions from base interfaces.
+If two base interfaces define the same attribute, the attribute is
+inherited from the most specific interface. For example, with::
+
+ >>> class IBase(zope.interface.Interface):
+ ...
+ ... def foo():
+ ... "base foo doc"
+
+ >>> class IBase1(IBase):
+ ... pass
+
+ >>> class IBase2(IBase):
+ ...
+ ... def foo():
+ ... "base2 foo doc"
+
+ >>> class ISub(IBase1, IBase2):
+ ... pass
+
+ISub's definition of foo is the one from IBase2, since IBase2 is more
+specific that IBase::
+
+ >>> ISub['foo'].__doc__
+ 'base2 foo doc'
+
+Note that this differs from a depth-first search.
+
+Sometimes, it's useful to ask whether an interface defines an
+attribute directly. You can use the direct method to get a directly
+defined definitions::
+
+ >>> IBase.direct('foo').__doc__
+ 'base foo doc'
+
+ >>> ISub.direct('foo')
+
+Specifications
+--------------
+
+Interfaces and declarations are both special cases of specifications.
+What we described above for interface inheritance applies to both
+declarations and specifications. Declarations actually extend the
+interfaces that they declare::
+
+ >>> class Baz(object):
+ ... zope.interface.implements(IBaz)
+
+ >>> baz_implements = zope.interface.implementedBy(Baz)
+ >>> baz_implements.__bases__
+ (<InterfaceClass __main__.IBaz>, <implementedBy ...object>)
+
+ >>> baz_implements.extends(IFoo)
+ True
+
+ >>> baz_implements.isOrExtends(IFoo)
+ True
+ >>> baz_implements.isOrExtends(baz_implements)
+ True
+
+Specifications (interfaces and declarations) provide an `__sro__`
+that lists the specification and all of it's ancestors::
+
+ >>> baz_implements.__sro__
+ (<implementedBy __main__.Baz>,
+ <InterfaceClass __main__.IBaz>,
+ <InterfaceClass __main__.IFoo>,
+ <InterfaceClass __main__.IBlat>,
+ <InterfaceClass zope.interface.Interface>,
+ <implementedBy ...object>)
+
+
+Tagged Values
+=============
+
+Interfaces and attribute descriptions support an extension mechanism,
+borrowed from UML, called "tagged values" that lets us store extra
+data::
+
+ >>> IFoo.setTaggedValue('date-modified', '2004-04-01')
+ >>> IFoo.setTaggedValue('author', 'Jim Fulton')
+ >>> IFoo.getTaggedValue('date-modified')
+ '2004-04-01'
+ >>> IFoo.queryTaggedValue('date-modified')
+ '2004-04-01'
+ >>> IFoo.queryTaggedValue('datemodified')
+ >>> tags = list(IFoo.getTaggedValueTags())
+ >>> tags.sort()
+ >>> tags
+ ['author', 'date-modified']
+
+Function attributes are converted to tagged values when method
+attribute definitions are created::
+
+ >>> class IBazFactory(zope.interface.Interface):
+ ... def __call__():
+ ... "create one"
+ ... __call__.return_type = IBaz
+
+ >>> IBazFactory['__call__'].getTaggedValue('return_type')
+ <InterfaceClass __main__.IBaz>
+
+Tagged values can also be defined from within an interface definition::
+
+ >>> class IWithTaggedValues(zope.interface.Interface):
+ ... zope.interface.taggedValue('squish', 'squash')
+ >>> IWithTaggedValues.getTaggedValue('squish')
+ 'squash'
+
+Invariants
+==========
+
+Interfaces can express conditions that must hold for objects that
+provide them. These conditions are expressed using one or more
+invariants. Invariants are callable objects that will be called with
+an object that provides an interface. An invariant raises an `Invalid`
+exception if the condition doesn't hold. Here's an example::
+
+ >>> class RangeError(zope.interface.Invalid):
+ ... """A range has invalid limits"""
+ ... def __repr__(self):
+ ... return "RangeError(%r)" % self.args
+
+ >>> def range_invariant(ob):
+ ... if ob.max < ob.min:
+ ... raise RangeError(ob)
+
+Given this invariant, we can use it in an interface definition::
+
+ >>> class IRange(zope.interface.Interface):
+ ... min = zope.interface.Attribute("Lower bound")
+ ... max = zope.interface.Attribute("Upper bound")
+ ...
+ ... zope.interface.invariant(range_invariant)
+
+Interfaces have a method for checking their invariants::
+
+ >>> class Range(object):
+ ... zope.interface.implements(IRange)
+ ...
+ ... def __init__(self, min, max):
+ ... self.min, self.max = min, max
+ ...
+ ... def __repr__(self):
+ ... return "Range(%s, %s)" % (self.min, self.max)
+
+ >>> IRange.validateInvariants(Range(1,2))
+ >>> IRange.validateInvariants(Range(1,1))
+ >>> IRange.validateInvariants(Range(2,1))
+ Traceback (most recent call last):
+ ...
+ RangeError: Range(2, 1)
+
+If you have multiple invariants, you may not want to stop checking
+after the first error. If you pass a list to `validateInvariants`,
+then a single `Invalid` exception will be raised with the list of
+exceptions as it's argument::
+
+ >>> from zope.interface.exceptions import Invalid
+ >>> errors = []
+ >>> try:
+ ... IRange.validateInvariants(Range(2,1), errors)
+ ... except Invalid, e:
+ ... str(e)
+ '[RangeError(Range(2, 1))]'
+
+And the list will be filled with the individual exceptions::
+
+ >>> errors
+ [RangeError(Range(2, 1))]
+
+
+ >>> del errors[:]
+
+Adaptation
+==========
+
+Interfaces can be called to perform adaptation.
+
+The semantics are based on those of the PEP 246 adapt function.
+
+If an object cannot be adapted, then a TypeError is raised::
+
+ >>> class I(zope.interface.Interface):
+ ... pass
+
+ >>> I(0)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+
+
+unless an alternate value is provided as a second positional argument::
+
+ >>> I(0, 'bob')
+ 'bob'
+
+If an object already implements the interface, then it will be returned::
+
+ >>> class C(object):
+ ... zope.interface.implements(I)
+
+ >>> obj = C()
+ >>> I(obj) is obj
+ True
+
+If an object implements __conform__, then it will be used::
+
+ >>> class C(object):
+ ... zope.interface.implements(I)
+ ... def __conform__(self, proto):
+ ... return 0
+
+ >>> I(C())
+ 0
+
+Adapter hooks (see __adapt__) will also be used, if present::
+
+ >>> from zope.interface.interface import adapter_hooks
+ >>> def adapt_0_to_42(iface, obj):
+ ... if obj == 0:
+ ... return 42
+
+ >>> adapter_hooks.append(adapt_0_to_42)
+ >>> I(0)
+ 42
+
+ >>> adapter_hooks.remove(adapt_0_to_42)
+ >>> I(0)
+ Traceback (most recent call last):
+ ...
+ TypeError: ('Could not adapt', 0, <InterfaceClass __main__.I>)
+
+__adapt__
+---------
+
+ >>> class I(zope.interface.Interface):
+ ... pass
+
+Interfaces implement the PEP 246 __adapt__ method.
+
+This method is normally not called directly. It is called by the PEP
+246 adapt framework and by the interface __call__ operator.
+
+The adapt method is responsible for adapting an object to the
+reciever.
+
+The default version returns None::
+
+ >>> I.__adapt__(0)
+
+unless the object given provides the interface::
+
+ >>> class C(object):
+ ... zope.interface.implements(I)
+
+ >>> obj = C()
+ >>> I.__adapt__(obj) is obj
+ True
+
+Adapter hooks can be provided (or removed) to provide custom
+adaptation. We'll install a silly hook that adapts 0 to 42.
+We install a hook by simply adding it to the adapter_hooks
+list::
+
+ >>> from zope.interface.interface import adapter_hooks
+ >>> def adapt_0_to_42(iface, obj):
+ ... if obj == 0:
+ ... return 42
+
+ >>> adapter_hooks.append(adapt_0_to_42)
+ >>> I.__adapt__(0)
+ 42
+
+Hooks must either return an adapter, or None if no adapter can
+be found.
+
+Hooks can be uninstalled by removing them from the list::
+
+ >>> adapter_hooks.remove(adapt_0_to_42)
+ >>> I.__adapt__(0)
+
+
+.. [#create] The main reason we subclass `Interface` is to cause the
+ Python class statement to create an interface, rather
+ than a class.
+
+ It's possible to create interfaces by calling a special
+ interface class directly. Doing this, it's possible
+ (and, on rare occasions, useful) to create interfaces
+ that don't descend from `Interface`. Using this
+ technique is beyond the scope of this document.
+
+.. [#factory] Classes are factories. They can be called to create
+ their instances. We expect that we will eventually
+ extend the concept of implementation to other kinds of
+ factories, so that we can declare the interfaces
+ provided by the objects created.
+
+.. [#compat] The goal is substitutability. An object that provides an
+ extending interface should be substitutable for an object
+ that provides the extended interface. In our example, an
+ object that provides IBaz should be usable whereever an
+ object that provides IBlat is expected.
+
+ The interface implementation doesn't enforce this.
+ but maybe it should do some checks.