Chris Withers wrote:
> Philipp von Weitershausen wrote:
>>> ...hence the quotes. It's a "function" in that I want to use it as an 
>>> adapter that doesn't need to be instantiated by a factory before being 
>>> used.
>> All adapters need to be instantiated. 
> Why?
> def myStrAdapter(something):
>     return str(something)
> This function adapts strings to integers, why would it need to be 
> instantiated?

I'm not sure this helps (I'm not quite sure what you're trying to do, it
seems a bit crazy), but the realisation that functions could be adapter
factories hit me at some point.

So, when you do an adapter lookup like

foo = IFoo(context)


foo = getAdapter(context, IFoo)

or similarly for getMultiAdapter, the CA will:

 1. Find the most appropriate adapter registration by looking at the
interfaces on context and finding the most specific adapter to IFoo
 2. Call that adapter registration's factory

A factory is just a callable that takes the context (or multiple context's
in the case of a multi-adapter). A class, of course, is a good factory, so
if you have:

class FooAdapter(object):

    def __init__(self, context):
        self.context = context

and then <adapter factory=".foo.FooAdapter" />

Then getting an adapter is the same as calling foo.FooAdapter(context) - you
get an object providing IFoo by calling the factory.

You could instead do:

def fooFactory(context):
    newAdapter = FooAdapter(context)
    return newAdapter

<adapter factory=".foo.fooFactory" />

Now, getting the IFoo adapter means calling fooFactory(context). Of course,
it still returns an object providing IFoo, so the contract is still valid.

Incidentally, we use this approach in Plone to fish things out of the ZODB.
You can adapt an object to IPortletAssignments, and we have a factory
function that finds an assignment container (a persistent btree container,
basically) in that object's annotations and returns it. This was a lot less
work than making a dumb transient adapter class that implemented all the
methods of IPortletAssignments (which is a sub-interface of IContainer, so
it has all the dict-like behaviour) and proxied each method call to
annotations on its context. The calling code doesn't care though:

assignments = IPortletAssignments(context)
assignments['my_new_portlet'] = MyNewPortlet()

And of course, if the object wasn't annotatable (say it was a transient
object originating from an SQL database) we could register a different

The important point here is that the adapter factory is called each time you
do an adapter lookup. In the most common case, the factory is just a class,
but it could be any callable. If you call a class, you get a new object of
that class, and hence adapter instances tend to be transient, but you could
have a different factory that wasn't.

>> No. You always register a factory which is called upon lookup. That's 
>> because adapters are context-dependent and thus need to be instantiated 
>> every time you look them up.
> What if they're not context-dependent as in my example above?
> ultimately, I'm looking to replace code like the following:
> convertors = {
>    int:{str:str,datetime:datetime},
>    str:(int:int,datetime:datetime},
> }
> def convert(x,y):
>     return convertors[type(x)][type(y)](x)
> ...if you see what I mean. Apologies for the trivial examples, but these 
> are real problems...

I still think this sounds a little over-complicated, but I'm guessing it's
just because you're de-badging the examples. If convert(x,y) was a
multi-adapter factory, then the above should work.

View this message in context:
Sent from the Zope3 - dev mailing list archive at

Zope3-dev mailing list

Reply via email to