"Updating" lambda functions

Bengt Richter bokr at oz.net
Thu Sep 16 16:58:58 EDT 2004


On 16 Sep 2004 14:07:20 GMT, Oliver Fromme <olli at haluter.fromme.com> wrote:

>Hi,
>
>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?
>
>Best regards
>   Oliver
>
>-- 
>Oliver Fromme, Konrad-Celtis-Str. 72, 81369 Munich, Germany
>
>``All that we see or seem is just a dream within a dream.''
>(E. A. Poe)

You could exploit the way functions become bound methods, e.g.,

 >>> fu = lambda x: x
 >>> fu = (lambda f,x: f(x) + 17).__get__(fu)
 >>> fu = (lambda f,x: f(x) * 3).__get__(fu)
 >>> fu(1)
 54
 >>> fu(0)
 51
 >>> fu(-15)
 6
 >>> fu(-16)
 3
 >>> fu(1,2)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: <lambda>() takes exactly 2 arguments (3 given)
 >>> fu
 <bound method ?.<lambda> of <bound method ?.<lambda> of <function <lambda> at 0x008FD8B0>>>

or, you could make a magic function-composing object with magic composing properties,
exploiting the method-making mechanism in a different way, e.g.,

 >>> class FC(object):
 ...     def __setattr__(self, name, f):
 ...         if not hasattr(self, name): self.__dict__[name] = [f]
 ...         else: self.__dict__[name].append(f)
 ...     def __getattribute__(self, name):
 ...         if name == '__dict__': return object.__getattribute__(self, '__dict__')
 ...         return type(self).__dict__['_xfuns'].__get__(
 ...             object.__getattribute__(self,name))
 ...     def _xfuns(flist, x):
 ...         for f in flist: x = f(x)
 ...         return x
 ...
 >>> fc = FC()
 >>> fc.fu = lambda x: x
 >>> fc.fu = lambda x: x + 17
 >>> fc.fu = lambda x: x * 3
 >>> fc.fu(1)
 54
 >>> fc.fu(0)
 51
 >>> fc.fu(-15)
 6
 >>> fc.fu(1,2)
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: _xfuns() takes exactly 2 arguments (3 given)
 >>> fc.bar = lambda x: x*3
 >>> fc.bar = lambda x: x+10
 >>> fc.bar(0)
 10
 >>> fc.bar(2)
 16
 >>> fc.fu(-18)
 -3

All just to explore python's features, not to recommend specific uses ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list