[Python-Dev] Serial function call composition syntax foo(x, y) -> bar() -> baz(z)

Bengt Richter bokr at oz.net
Fri Feb 17 22:59:19 CET 2006


Cut to the chase: how about being able to write

    baz(bar(foo(x, y)),z)

serially as

    foo(x, y) -> bar() -> baz(z)

via the above as sugar for

    baz.__get__(bar.__get__(foo(x, y))())(z)

?

I.e., you'd have self-like args to receive results from upstream. E.g.,

 >>> def foo(x, y): return 'foo(%s, %s)'%(x,y)
 ...
 >>> def bar(stream): return 'bar(%s)'%stream
 ...
 >>> def baz(stream, z): return 'baz(%s, %s)'%(stream,z)
 ...
 >>> x = 'ex'; y='wye'; z='zed'

then (faked)
 >>> foo(x, y) -> bar() -> baz(z)
 'baz(bar(foo(ex, wye)), zed)'

would do (actual) 
 >>> baz.__get__(bar.__get__(foo(x, y))())(z)
 'baz(bar(foo(ex, wye)), zed)'

(or if the callable has no __get__, use new.instancemethod methodology behind the scenes)

This is to provide an alternative to serial composition of function calls
as methods of returned objects, which sometimes looks nice, but may have strange
coupling of types and functionality. E.g. you could define classes to be able
to write the above as

    foo(x, y).bar().baz(z)    

and that's effectively what is being done by the -> notation. The __get__ stuff
is really just on-the-fly bound method generation without passing the instance
class argument. But -> allows the composition without creating knowledge coupling
between the foo, bar, and baz sources. It just has to be realized that this way
of composition works via the first argument in passing through prior results.

BTW, note that in the above foo(x, y) is just the first expression result being
fed into the chain, so a constant or any expression can be the first, since
it just becomes the argument for the innermost nested call. I.e.,

    'abcd' -> binascii.hexlify()
for
    >>> new.instancemethod(binascii.hexlify, 'abcd', str)()
    '61626364'

Note that it's valid to leave off the () -- IOW
simply,  a->b is sugar for b.__get__(a)  (or the instancemethod equivalent)

(faked) 
 'expr' -> baz
 <bound method ?.baz of 'expr'>
(actual)
 >>> baz.__get__('expr')
 <bound method ?.baz of 'expr'>

and then
 >>> baz.__get__('expr')('zee')
 'baz(expr, zee)'

What do you think? 

Regards,
Bengt Richter



More information about the Python-Dev mailing list