Anonymous functions (was Re: Some python comments/questions)

Tim Peters (tim@ksr.com)
Tue, 12 Oct 93 14:43:54 -0400

> 2) It would often be useful if there was some way to create function
> objects without binding them to some name. You can do it with
> something like
>
> def makefuncobj ():
> def tmp (x, y, z):
> return (x + y * z)
> return(tmp)
>
> a = makefuncobj()
>
> but you need to define a new makefuncobj for every function you
> wish to dynamically create, which takes some of the dynamism
> out of it :-). ...

You might find the following handy, for creating simple "one-liner"
functions on the fly:

from string import find

def func( f ):
i = find( f, ':' )
if i < 0:
raise ValueError, 'need colon in function string ' + `f`

args, body = f[:i], f[i+1:]
f = 'def f(' + args + '): return ' + body

bad = 1 # guilty until proven innocent
try:
exec( f ) # creates local func 'f'
bad = 0
finally:
if bad:
print 'Error in func: couldn\'t exec ' + `f`

return f

This takes a string of the form

[arglist] ':' expression

as its argument, and returns the function defined by

'def f(' arglist '): return ' expression

The name 'f' is local to the invocation of 'func', so effectively
vanishes when 'func' returns (the binding of the _name_ 'f' to the
function object vanishes, but the function object itself does not); so
from the point of view of the caller, the function returned by 'func' is
anonymous (cannot interfere with name bindings in the caller, or indeed
even be invoked by name).

For example, given function

def map( f, x ):
y = []
for e in x:
y.append( f(e) )
return y

we have

>>> map( func('x: x*x'), range(8) )
[0, 1, 4, 9, 16, 25, 36, 49]
>>>

Or

>>> flist = map( func, ['x:x+x', 'y:y*y', 'z:42'] )
>>> for f in flist:
... print f(3)
...
6
9
42
>>>

I often find 'func' to be handy, in conjunction with LISPish functions
like 'map', when doing interactive data crunching.

> You could almost do it with exec(), I'd think, except that exec()
> doesn't return its value.

Right, that's why the exec is packaged inside a function here.

> Are multi-line expressions even allowed?

The context ("allowed" where?) wasn't clear to me. exec will crunch any
legit Python program text, and it's certainly possible to generalize
'func' to allow creating anonymous functions built out of arbitrary
Python code. But note that representing complex functions as strings
gets clumsy, because you have to get the newlines, and the right amount
of leading indentation, in the right places (or, define an un-Python-like
string representation, and program a fancier 'func' to translate that
into legit Python before handing it to 'exec').

the-function-that-is-named-is-not-the-true-function-ly y'rs - tim

Tim Peters tim@ksr.com
not speaking for Kendall Square Research Corp