Ian Bicking: the old part of his blog

Re: More on Python Metaprogramming

By the way, Zope 3 has a few more things like 'implements' that are being used more and more as Zope 3 matures. Most commonly, these things are used on interfaces, which is the biggest in-language 'DSL' that Zope 3 has. A common thing is to make constraints about what kind of objects a container might hold, or what kind of containers an object might be placed in.

from zope.interface import Interface, Attribute
from zope.app.container.constraints import contains, containers
from zope.app.container.interfaces import IContainer, IContained

class IThing(Interface):
    """ Just a thing. """
    about = Attribute("What this thing is about.")

class IThingHolder(IContainer):
    """ A container that can hold things. """
    # This sets up a constraint on the container so that it can only
    # hold objects that implement the IThing interface
    contains(IThing)

class IThingContained(IContained):
    """
    An interface stating that things can be contained in thing holders.
    """
    containers(IThingHolder)

This is much better than an older way of doing the same thing.

from zope.app.container.constraints import ContainerTypesConstraint
from zope.app.container.constraints import ItemTypePrecondition
import zope.schema

class IThingHolder(IContainer):
    """ A container that can hold things. """
    def __setitem__(name, object):
        """
        Redefine __setitem__  in the interface so that a precondition
        can be set to restrict contained objects to IThings
        """
    __setitem__.precondition = ItemTypePrecondition(IThing)

class IThingContained(IContained):
    """ Put a constraint on the __parent__ field """
    __parent__ = zope.schema.Field(
        constraint=ContainerTypesConstraint(IContentContainer),
        )

There are other little things around that also have made life a little bit nicer, such as object adaptation.

from zope.interface import implements
from zope.app import zapi
from example.interfaces import ISquarePeg, IRoundHole

# Old Way
class OldSquarePegToRoundHoleAdapter(object):
    # even older style would be __implements__ = IRoundHole
    implements(IRoundHole)
    __used_for__ = ISquarePeg

    # implementation....

# New Way
class SquarePegToRoundHoleAdapter(object):
    implements(IRoundHole)
    zapi.adapts(ISquarePeg)

It's a nice showcase for what is possible. What's nicest about this is that 'implements()', 'adapts()', and so on can be looked up easily in an API documentation tool. Trying to remember all of the __funny_names__ is not so easy.

Comment on More on Python Metaprogramming
by Jeff Shell