[Python-3000] Adaptation vs. Generic Functions

Guido van Rossum guido at python.org
Thu Apr 6 02:05:51 CEST 2006


On 4/5/06, Tim Hochberg <tim.hochberg at cox.net> wrote:
> It seems like you can chain protocols like that simply by setting up an
> appropriate default_adapter method. For example, if we already had a
> pprinter protocol, we could define one that subclassed it and customized it:
>
> class CustomPPrintProtocol(Protocol):
>      def default_adapter(self, *args):
>          return pprinter(*args)
> hex_pprinter = CustomPPrintProtocol("hex_pprinter")
>
> @hex_pprinter.register_for(int, long):
> def hex_pprint(obj):
>     return hex(obj)
>
>
> While on the subject of pretty print, I just hacked pretty print to
> allow site wide customizations using Protocols. In addition to adding
> the protocol class wholesale (it's not on my python path right now), it
> took only three lines worth of changes. I added:
>
>     simple_formatter = Protocol('simple_formatter')
>     simple_formatter.register(repr, object)
>
>
> Near the top and changed _safe_repr to use simple_formatter:
>
>     def _safe_repr(object, context, maxlevels, level):
>         # ....
>         rep = simple_formatter(object) # was repr(object)
>         return rep, (rep and not rep.startswith('<')), False
>
>
> With that in place, I can easily do sitewise changes to stuff like
> integer display:
>
>     import pprint
>     data = ( # From fbots librarybook
>         "this is a string", [1, 2, 3, 4], ("more tuples",
>         1.0, 2.3, 4.5), "this is yet another string"
>         )
>
>     pprint.pprint(data)
>     print
>     pprint.simple_formatter.register(hex, int, long)
>     pprint.pprint(data)
>
> ==>
>
>     ('this is a string',
>      [1, 2, 3, 4],
>      ('more tuples', 1.0, 2.2999999999999998, 4.5),
>      'this is yet another string')
>
>     ('this is a string',
>      [0x1, 0x2, 0x3, 0x4],
>      ('more tuples', 1.0, 2.2999999999999998, 4.5),
>      'this is yet another string')
>
> Nice!
>
> I expect that with another dozen lines of code I could make custom
> pretty printers possible, although the way the customization happens
> might be a little kludgy. I'll look into it.

Neat indeed.

What I'd like to see is how this changes if we use a generic functions
(multiple dispatch) implementation instead of adaptation. Adaptation
is pretty much isomorphic with a generic function of one argument (see
my blog). But the register_for() method couldn't (shouldn't) interpret
multiple arguments as multiple registrations; it should probably take
this to match the call signature.

Then multiple registrations would slightly more awkward; fortunately
they don't have to be as ugly as they were in my earlier post since
you can stack them:

    @hex_pprinter.register_for(int, long)
   def ...

could become

    @hex_pprinter.register_for(int)
    @hex_pprinter.register_for(long)
    def ...

I also wonder if the explicit (non-decorator) registration API is rare
enough that we could use a single register() method that favors use as
a decorator but can be used for explicit registration in a pinch. Then
the decorator could look like this:

    @hex_pprinter.register(int)
    def ...

and explicit registration could be done like this:

   pprint.simple_formatter.register(int)(hex)
   pprint.simple_formatter.register(long)(hex)

For multiple-argument signatures the call would become e.g.

   foo.register(int, str, C)(myfunc)

which isn't so bad compared to

  foo.register(myfunc, (int, str, C))

--
--Guido van Rossum (home page: http://www.python.org/~guido/)


More information about the Python-3000 mailing list