[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