How do I dynamically create functions without lambda?

Scott David Daniels scott.daniels at acm.org
Fri Jan 27 22:21:19 EST 2006


Steven D'Aprano wrote:
> On Fri, 27 Jan 2006 11:41:56 -0800, Kay Schluehr wrote:
> 
>> Russell wrote:
>>> I want my code to be Python 3000 compliant, and hear
>>> that lambda is being eliminated. The problem is that I
>>> want to partially bind an existing function with a value
>>> "foo" that isn't known until run-time:
>>>
>>>    someobject.newfunc = lambda x: f(foo, x)
>>>
>>> The reason a nested function doesn't work for this is
>>> that it is, well, dynamic. I don't know how many times
>>> or with what foo's this will be done.
>>>
>>> Now, I am sure there are a half-dozen ways to do this.
>>> I just want the one, new and shiny, Pythonic way. ;-)
>> If you want to code partial application without lambda I recommend
>> using the code presented in the accepted PEP 309 that will be
>> implemented in the functional module in Python 2.5.
>>
>> http://www.python.org/peps/pep-0309.html
> 
> 
> Fascinating. A couple of thoughts:
> 
> - I really wish that people would make up their minds about what currying
> is, and how it differs from partials and closures. If the people who
> do know can't agree, how do they expect the rest of us to understand?

Me too, but I disagree with the people who won the argument on the name.
Curry derives its name from the mathematician who formulated the
Curry-Howard isomorphism that says a function of multiple arguments
can be expressed as a function taking a single argument which returns a
function which takes a single argument which... takes a single argument
and returns the result of the original multi-argument function.  This
isomorphism means that you need only define functions which take single
arguments.  In some functional languages, functions are called adjacent
to their arguments, and a function which looks like it takes multiple
arguments is actually taking a single argument of a tuple.

The Curry recipe I put in the Python Cookbook did the analogous thing
for the Python language, since there is no way for a "Curry" argument
to know when to call the underlying function, rather than simply
accumulate arguments.

> - What, if anything, is the difference between a closure and an iterator?
> Is an iterator just a closure wrapped up with an API?

A closure is a function and the environment it was created in.
So, for example, the result of calling:

     def multiplier(n):
         def result(m):
             return n * m

multiplier(2) returns a closure (the function called result and its
environment where n is set to 2).

An iterator is a different beasty.

> - The first sample code seems needlessly confusing to me. It gives:
> 
> class partial(object):
>     def __init__(*args, **kw):
>         self = args[0]
>         self.fn, self.args, self.kw = (args[1], args[2:], kw)
>     def __call__(self, *args, **kw):
>         if kw and self.kw:
>             d = self.kw.copy()
>             d.update(kw)
>         else:
>             d = kw or self.kw
>         return self.fn(*(self.args + args), **d)
> 
> It seems to me to needlessly break the convention that the first argument
> is self.
Actually, it does, but only because the second doesn't break it as well.

 > to no benefit and considerable reduction in clarity. After some
> experimentation, I worked out what it was doing, and realised that it
> would work just as well but much less obscurely if the __init__ function
> was written as:
> 
>     def __init__(self, fn, *args, **kw):
>         self.fn, self.args, self.kw = fn, args, kw

It would pretty much work like this, _but_ you could not used named args
of self or fn when using one of these things.

A better definition:
     class partial(object):
         def __init__(*args, **kw):
             self = args[0]
             self.fn, self.args, self.kw = (args[1], args[2:], kw)
         def __call__(*args, **kw):
             self = args[0]
             if kw and self.kw:
                 d = self.kw.copy()
                 d.update(kw)
             else:
                 d = kw or self.kw
             return self.fn(*(self.args + args[1:]), **d)

Now you can, for example:

def function(self, other, fn):
     return fn([self, other])

defaults = partial(function, self=object(), fn=repr)
print defaults(other=3), defaults(self='self', other=3)

The fancy-schmancy stuff is to keep from hiding some names.  I suspect
both args and kw have this problem as well.  It might have been
reasonable to call them __self, __function, __args, and __kwargs
and do it your way.

> - It seems a shame to me that having created a partial _function_ using
> that technique, type(partial(...)) returns <class partial>. It would be
> nicer if the type made it more obvious that the instance was callable.
But callable(defaults) returns True.  You will eventually learn that
partial is callable, just as you know "type"s are callable.  Seeing
that it is class partial, you can (if you are nosey), see what the
arguments already provided are (so you could get a nicer print).
For example, adding a method to partial:

     def __repr__(self):
         return 'partial(%r, *%r, **%r)' % (self.fn, self.args, self.kw)

> Something like <callable class partial> perhaps? Is there any way for a
> class to customise the type representation?

-- 
-Scott David Daniels
scott.daniels at acm.org



More information about the Python-list mailing list