[Python-3000] Generic functions

Tim Hochberg tim.hochberg at ieee.org
Tue Apr 4 17:04:34 CEST 2006


Phillip J. Eby wrote:
> At 11:03 PM 4/3/2006, Ian Bicking wrote:
> 
>>Guido van Rossum wrote:
>>
>>>On 4/3/06, Ian Bicking <ianb at colorstudy.com> wrote:
>>>
>>>>As an alternative to adaptation, I'd like to propose generic functions.
>>>>  I think they play much the same role, except they are much simpler to
>>>>use and think about.
>>>
>>>Given that Phillip Eby is another proponent of generic functions I
>>>seriously doubt the latter.
> 
> 
> Hm.  :)
> 
> Rather than branch all over the map, let me focus for a moment on a 
> very simple type of generic function - the kind that is essentially 
> equivalent to PEP 246-style adaptation.  This will make it easier to 
> see the relationship.
> 
> In the RuleDispatch package, these simple generic functions are 
> defined using dispatch.on and f.when(), like this:
> 
>      import dispatch
> 
>      @dispatch.on('ob')  # name of the argument to dispatch based on
>       def pprint(ob):
>            """This is a pretty-print function"""
> 
>      @pprint.when(object)
>      def pprint(ob):
>           print repr(ob)
> 
>      @pprint.when(list)
>       def pprint(ob):
>            # code for the list case
> 
> Now, this is exactly equivalent to the much longer code that one 
> would write to define an IPrettyPrintable interface with a pprint() 
> method and adapter classes to define the implementation 
> methods.  Yes, it's a convenient example - but it also corresponds to 
> a fairly wide array of problems, that also happen to be a significant 
> number of uses for adaptation.

Rewriting this using "distributed" adapters looks like this:

 >>> pprint = Protocol('pprint')

 >>> @pprint.when(object)
... def pprint_obj(obj):
...     print repr(obj)

 >>> @pprint.when(list)
... def pprint_list(obj):
...     print 'pretty(%r)' % obj


Pretty similar! Stealing the when decorator cleans up the use of 
copy_reg.pickle rewrite a bit as well. I imagine that where these would 
diverge is when there is more than one argument.


Regards,

-tim


P.S., Here's Protocol. To save a few bytes I've stripped classic class 
support.


class Protocol(object):
     all_protocols = set()
     def __init__(self, name):
         self.name = name
         self.registry = {}
         self.all_protocols.add(self)
     def __repr__(self):
         return "<protocol %r>" % self.name
     __str__ = __repr__
     def __call__(self, obj):
         #~ mro = _get_mro(obj)
         mro = type(obj).__mro__
         for cls in mro:
             adapter = self.registry.get(cls, None)
             if adapter is not None:
                 return adapter(obj)
         raise ValueError('adapter not found')
     def register(self, adapter, *types):
         if not callable(adapter):
             raise TypeError("adapters must be callable")
         for t in types:
             self.registry[t] = adapter
     def when(self, *types):
         def decorator(adapter):
             self.register(adapter, *types)
             return adapter
         return decorator






More information about the Python-3000 mailing list