[Tutor] lambda problem

Corran Webster cwebster@nevada.edu
Thu, 6 Apr 2000 09:23:23 -0700

> Dear Tutors,
> Isn't it possible to use a lambda inside a lamda?

The short answer is yes - see below.

> 2. With a "lambda in lambda" shortcut:
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> li=map(lambda y:map(lambda x:x+y, [30,40]),[1,2,3])
> Traceback (innermost last):
>   File "<pyshell#18>", line 1, in ?
>     li=map(lambda y:map(lambda x:x+y, [30,40]),[1,2,3])
>   File "<pyshell#18>", line 1, in <lambda>
>     li=map(lambda y:map(lambda x:x+y, [30,40]),[1,2,3])
>   File "<pyshell#18>", line 1, in <lambda>
>     li=map(lambda y:map(lambda x:x+y, [30,40]),[1,2,3])
> NameError: y
> The inner lambda seems not to recognize the variable y defined by the
> outer lambda.  Do I want something impossible or do I misunderstand how
> lambda is functionning?

The problem is that the inner lambda has no knowledge of the variable y
(this is indicated by the NameError

This is not a problem particular to lambdas, but to any python function.
What you are doing is effectively:

def f(y):
  def g(x):
    # can't see y in here!
    return x+y
  map(g, [30,40])

map(f, [1, 2, 3])

and this won't work either.  The problem is how Python scopes variables -
there is no nesting of scopes, so there is no way (without severe hackish
wizardry) for g to get any information about f's variables.  This is
probably because functions in Python are first-class objects, and so it's
unclear whether the 'y' you want is the one from f, or perhaps one from
some other function which has managed to get ahold of g (perhaps because f
returned g) and is calling it.

There is a work-around, which is standard to the point of being idiomatic
for lambdas in Python.  By passing y in as a default argument to the second
lambda, you get the result you want:

>>> li = map(lambda y: map(lambda x, y=y: x+y, [30,40]),[1,2,3])
>>> li
[[31, 41], [32, 42], [33, 43]]

This isn't entirely foolproof (you can get weird results if y is mutable
and the lambda mutates it somehow), and is definitely hackish, but it works.