"Updating" lambda functions

Robert Brewer fumanchu at amor.org
Thu Sep 16 17:19:36 CEST 2004


Oliver Fromme wrote:
> I'm trying to write a Python function that parses
> an expression and builds a function tree from it
> (recursively).
> 
> During parsing, lambda functions for the the terms
> and sub-expressions are constructed on the fly.
> Now my problem is lazy evaluation.  Or at least I
> think it is.  :-)
> 
> I need to "update" a lambda function, like this:
> 
>         fu = lambda x: x
>         ...
>         fu = lambda x: fu(x) + 17
>         ...
>         fu = lambda x: fu(x) * 3
> 
> Of course that doesn't work, because fu is resolved
> when the lambda is called, not when it's defined, so
> I'll run into an endless recursion.
> 
> My current solution is to define a helper function
> which passes the lambda through its argument:
> 
>         def add_17 (fu):
>                 return lambda x: fu(x) + 17
> 
>         def mul_3 (fu):
>                 return lambda x: fu(x) * 3
> 
>         fu = lambda x: x
>         ...
>         fu = add_17(fu)
>         ...
>         fu = mul_3(fu)
> 
> That works, but it strikes me as unclean and ugly.
> Is there a better way to do it?

Two approaches, both using bytecode hacks, so they are CPython-specific:

One, if all your use cases are simple, wrap the lambda in an object,
then override __mul__ and __add__, etcetera, for that object. Then
write:

>>> fu = Expression(lambda x: x)
>>> fu2 = fu + 17
>>> fu2
Expression(lambda x: x + 17)
>>> fu3 = fu2 * 3
>>> fu3
Expression(lambda x: (x + 17) * 3)

See my http://www.aminus.org/rbre/python/logic.py for an example of
wrapping lambdas. I override __add__ there to 'logical and' two
expressions together, so that fu + fu2 => fu and fu2.


Two, bind early. See
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/277940. That
solution only binds globals, but you can extend it to handle function
calls. Then special-case expr() inside the lambda, replacing it with the
existing expression. See my
http://www.aminus.org/rbre/python/codewalk.py for some examples of
binding more, earlier.

>>> fu = Expression(lambda x: x)
>>> fu2 = Expression(lambda x: expr(fu) + 17)
>>> fu2
Expression(lambda x: x + 17)
>>> fu3 = Expression(lambda x: expr(fu2) * 3)
>>> fu3
Expression(lambda x: (x + 17) * 3)



Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org



More information about the Python-list mailing list