[Python-3000] Adaptation vs. Generic Functions

Tim Hochberg tim.hochberg at cox.net
Wed Apr 5 22:44:22 CEST 2006


Walter Dörwald wrote:

> Guido van Rossum wrote:
>
>> Fascinating ideas in this thread!
>>
>> I spent some time blogging about this on artima:
>> http://www.artima.com/weblogs/viewpost.jsp?thread=155123
>>
>> I have to write my slides for a talk about Py3K later today, but I'll
>> be back. In the mean time I've rejected PEPs 245 and 246 in
>> expectation of something better that's imminent!
>
>
> What's still missing IMHO is a way for an adapter to defer to the next 
> adapter in the chain, i.e. something like:
>
> class Protocol(object):
>    def register(self, ...):
>       ...
>
>    def __call__(self, ...):
>       ...
>
>    def default(self, *args, **kwargs):
>       raise TypeError
>
>    def candidates(self, *args, **kwargs):
>       return type(args[0]).__mro__
>
>    def super(self, *args, **kwargs):
>       search = iter(self.candidates(*args, **kwargs))
>       for key in search:
>          if key in self.registry:
>             break
>       try:
>          return search.next()(*args, **kwargs)
>       except StopIteration:
>          return self.default(*args, **kwargs)
>
>
> With this an adapter could use the super() method to call the next 
> adapter in the chain:
>
> p = Protocol()
>
> @p.register(Foo)
> def p_foo(foo):
>    p.super(foo)

The concept seems good, but I find the implementation baffling, OK, I 
finally figured it out. It only seems to work once though -- you can't 
chain super calls. Why not simply raise a DeferToNextAdapter exception?  
That seems much simpler and it chains correctly.

class DeferToNextAdapter(Exception):
    pass

class Protocol(object):
     #....

     def __call__(self, *args):
         """Adapt supplied arguments to this protocol"""
         for key in self.signatures(args):
             try:
                 try:
                     adapter = self.registry[key]
                 except
                     pass
                 else:
                     return adapter(*args)
             except DeferToNextAdapter:
                  pass
         return self.default_adapter(*args)

p = Protocol()

@p.register(Foo)
def p_foo(foo):
   raise DeferToNextAdapter

=========================================

FWIW, I'm also not very enthusiastic about the inner try/except block 
that showed up at some point. The normal case is to fail here, so it 
seem like this results in unnecessary overhead. That's a minor issue though.

Regards,

-tim




More information about the Python-3000 mailing list