[Python-ideas] @partials = decorators

Ron Adam ron3200 at gmail.com
Sun Feb 16 08:22:25 CET 2014


On 02/10/2014 01:44 PM, Alex Rodrigues wrote:
> This is pretty cumbersome to write out every time so I wanted a function that could just be called on arbitrary histograms like side_by_side(data1.hist(bottom=0.1, log=True), data2.hist(bins=10)). The problem is that I do not have the axes available when I call the function and once I pass the plots to the function they have already been evaluated and there is no way to add arguments retroactively. With the continuation syntax it would be amazingly easier:
>
> def side_by_side(plot1, plot2):
>      fig = plt.figure()
>      ax1 = plt.subplot(121)
>      ax2 = plt.subplot(122)
>      plot1(ax=ax1)
>      plot2(ax=ax2)
>
> side_by_side(@data.hist(), @data.hist(log=True)) #Technically the first
> one doesn't need to be a continuation, but whatever.
>
> tldr; I like it and see a decent number of applications. Also I'm
> wondering if you'd have to chain continuations
> @@a('arg1')('arg2')('arg3').

These functions are more like partials, rather than continuations, which 
pause in the middle of the function.

No, you wouldn't need to chain them since each incomplete call returns a 
incomplete callable object.

So this works...

   _()(f)(a1)(a2)(a3) --> result


The latest version I have, ... it's evolving as I go...  has two parts.

     1.  A caller function.  Which attempts to call the function.
     2.  A callable holder object.  Which holds the incomplete call state.

Both of these take any number of arguments.  The only requirement is that 
the first item in the sequence of arguments be a callable.

You can be initiate the arguments with either the caller, or the holder, 
depending on weather or not you want to delay the initial call attempt.

The caller will try to call the function with the initially given arguments 
and if that fails, it instead returns a callable holder object.  When the 
holder is called, it will collect more arguments and pass those to the 
caller.  Which may return a final result or another holder.

If you apply a non callable object to these, it just gets returned.  That 
allows you to catch deferred results, and pass other things through.  A 
sort of explicit lazy evaluation.

So far, I've found these are pretty good at doing lambda calculus, 
flattening decorators, and can be useful in deferring a call in some 
situations where normally you would use a lambda function or a nested 
function definition.  And they may also be good at collecting non 
localised, or disjointed data.

It's also nice that they are higher order functions that accept most any 
callable.

The main issue is there is not a reliable way to get the argument count of 
builtin callable function or class.  Python functions have an arg_count 
attribute in the code object.  But builtin functions lack that attribute. 
(hint, hint...)

So for now, these are more conceptual than useful, as they will break under 
certain situations... like giving too many arguments, or if a TypeError 
exception comes from within the function instead of during the call process.

Cheers,
    Ron












More information about the Python-ideas mailing list