[Python-3000] Adaptation vs. Generic Functions

Tim Hochberg tim.hochberg at ieee.org
Thu Apr 6 04:50:22 CEST 2006


Guido van Rossum wrote:

[TAHs simple pprint customization example snipped]

>>
>>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))

FWIW, I consistently type protocol.register(type, adapter) instead of 
the other way around. The change you propose switches the order around 
to what seems natural and cleans up the API as well, so +1 from me.

I was sucessful on the pprint front. I'll clean up the example tomorrow 
and post either a URL or a diff (any preferences?) but here's how it's used:

##############

import pprint

# Any instance of pprint.PPrint is a separately cusomizable
# pretty printer. pprint.pprint is just another instance.

mypprint = pprint.PPrint()

# Some data I stole from the fbots librarybook for testing

data = (
     "this is a string", [1, 2, 3, 4], ("more tuples",
     1.0, 2.3, 4.5), "this is yet another string"
     )

# This just pprints as usual

pprint.pprint(data)

# So does this.

mypprint(data)

# Now we can register an adapter to mypprint and
# ints and longs will be printed in hex. Note
# that mypprint is not really an adapter, it just
# forwards register calls to an underlying
# Protocol. (Actually a SubProtocol that should handle
# "inheritance" correctly, although it's not well
# tested yet).

mypprint.register(hex, int, long)
mypprint(data)

# The output of this is still unchanged however.

pprint.pprint(data)

##############

This is pretty cool, but it's really only halfway there. Right now, only 
the 'basic' types that were previously handled by repr are handled by 
the custom formatter. So, you can't customize tuples and dicts and such 
that are hardcoded into _safe_repr and _format. The full solution tosses 
those into the formatter as well and gets rid of _safe_repr and _format 
altogether.

I have a feeling that once you start pulling on this thread the whole 
module will unravel and all that will be left is a couple of protocols 
and a bunch of helper functions. That would be cool to see, but it might 
take a while.

Regards,

-tim



More information about the Python-3000 mailing list