[Python-ideas] @partials = decorators

Ron Adam ron3200 at gmail.com
Sat Feb 8 18:55:56 CET 2014


On 02/06/2014 05:14 AM, Nick Coghlan wrote:> On 6 February 2014 20:34, Ron 
Adam<ron3200 at gmail.com>  wrote:

(clipped unrelated discussion)

 > As far as what you're proposing goes, is it essentially a way to
 > declare a function like (spelling out the lambdas fully):
 >
 >      def S(x):
 >          def _second(y):
 >              def _third(z):
 >                  return x(z)(y(z))
 >              return _third
 >          return _second
 >
 > As something much shorter like this:
 >
 >      def S (x)(y)(z):
 >          return x(z)(y(z))
 >
 > The main potential benefit I could see to a construct like that is
 > that it may allow the more consistent creation of closures that
 > support pickling, since the outer functions are guaranteed not to have
 > any side effects and to have argument capture as their*only*
 > significant state. This means that you could take the inner function,
 > pickle it along with its closure variables and reconstruct that at the
 > far end, only relying on the name of the outer function.
 >
 > Such a construct could also make decorator factories easier to write.
 >
 >      def decorator(f):
 >          # Do something with f
 >
 >      def decorator_factory(some, args, here)(f):
 >          # Do something with f, but have access to the bound args.
 >
 > There's an argument to be made that the extra parens in the function
 > header are too easy to miss, but I still see "make it easier to write
 > side-effect free closures" as an idea worth discussing further.


It's a different feature than the one I was suggesting, which was a type of 
continuations... but the two concepts are related and compatible.

I think the S(x)(y)(z):   is adding more complexity to function signatures 
which are already more complex than I like,  but there is an alternate 
option...


What if these *calls* were equivalent...

      S(x, y, z)  ==  S(x)(y)(z)

* There might need to be some additional device or syntax needed to make it 
work.  (* see '@' comments further down.)

That is on the call side, so the definition would still be the same.

     def(x, y, z): ...

Which is nice, because it gives us partials at a lower level which may have 
some advantages over a library function.  And it gives us a better way to 
define decorators.

     def  deco(func, *args, **kwds):
        ...


    deco(func, *args, **kwds) ==  deco(func)(*args, **kwds)
                              or  deco(func)(*args)(**kwds)


In effect making a decorators into partials.

     @deco
     def foo(...):
        ...


Hmmm...  Could the @ syntax be generalised in this case?

      @foo(func)    Partial waiting for rest...


Then the more general case...

      a_op = @foo(op)   # Partial waiting for rest.
      a_x = @a_op(x)
      a = a_x(y)

That would be cool, unifies decorators and partials with decorator syntax!


I think it's even back-words compatible if you allow this equivalency.

     def foo(x, y):
        ...

     @foo(x, y)  ==  foo(x, y)    # An identity partial


And the decorator case becomes...

     @partial
     def func():
       ...

And we get this equivalency as well....

     @partial == partial       # I think this could work.


The reason these things are interesting to me is that, I've been thinking 
about the order of function arguments and if there could be some 
generalised concepts that can be applied to that problem.  Being able to 
use normal functions effectively in these ways,  (with partials, and 
continuations), is related to the order of the arguments and how they are 
commonly used.

Cheers,
    Ron




More information about the Python-ideas mailing list