Reputation: 43
I'm trying to do the following, which is a representative example of what my final goal will be:
yu = lambda x: 0
for i in range(0,5):
yu = lambda x: i + yu(x)
Unfortunately, it returns:
RuntimeError: maximum recursion depth exceeded
when I do:
print yu(0)
The print statement should return 10.
What's the correct way to do this?
Upvotes: 2
Views: 9947
Reputation: 1951
Considering the answers you try to sum up 0, 1, 2, 3, 4. If that was right you could use the following lambda expression:
yu = lambda x: x + yu(x+1) if x<4 else x
For yu(0)
it delivers 10 as a result. The break condition is the value of x
which is required to stay smaller than 4 in order to add up.
Assuming that is what you desired to do, you should leave out the loop for a rather concise statement.
This lambda expression differentiates from the others in resulting in different values (other than 10, when not choosing 0 as the parameter x) depending on the given argument.
Upvotes: 0
Reputation: 45
facto = lambda f: f if f == 0 else f + facto(f-1)
print(facto(4))
Upvotes: 0
Reputation: 101
I believe I didn't fully understand your question, but could anyone check if this is what he meant?
I assumed you wouldn't need an iterator to generate a list of digits
yu = lambda x: x[0] + yu(x[1:]) if x!=[] else 0
Upvotes: 0
Reputation: 1122232
In the end, you have:
yu = lambda x: i + yu(x)
but yu
will be looked up at runtime, not when you constructed the lambda. Do this instead:
for i in range(0,5):
yu = lambda x, yu=yu: i + yu(x)
This does not return 10
, though. It returns 20
instead:
>>> yu = lambda x: 0
>>> for i in range(0,5):
... yu = lambda x, yu=yu: i + yu(x)
...
>>> yu(0)
20
because now i
is still looked up from the context (and by now the loop has finished so it's 4
). Solution? Move i
to a keyword argument too:
for i in range(0,5):
yu = lambda x, yu=yu, i=i: i + yu(x)
Now this works:
>>> yu = lambda x: 0
>>> for i in range(0,5):
... yu = lambda x, yu=yu, i=i: i + yu(x)
...
>>> yu(0)
10
Moral of the story? Bind your context properly to the scope of the lambda.
Upvotes: 5
Reputation: 365767
yu = lambda x: i + yu(x)
This makes yu
into a function that always calls itself, guaranteeing infinite recursion with no base case.
Why? Well, you've built a closure where yu
(and i
) are the local variables in the function or module that the for
loop is part of. That's not what you want; you want to close over the current values of yu
and i
, not the outer variables.
I'm not sure why you're even using lambda
in the first place. If you want to define a function and give it a name, use def
.
Here's an easy solution:
def yu(x): return 0
def make_new_yu(yu, i):
def new_yu(x): return i + yu(x)
return new_yu
for i in range(0, 5):
yu = make_new_yu(yu, i)
By making the wrapping explicit, the correct way to do it becomes the most obvious way to do it.
You can, of course, use a lambda
inside make_new_yu
without making things more confusing:
def make_new_yu(yu, i):
return lambda x: i + yu(x)
And you can even make the initial definition a lambda
if you want. But if you insist on not having any def
statements, you need to force the right values into the closure in some way, e.g., by using the default-value trick. That's much easier to get wrong—and harder to read once you've done it.
If you want an intuitive understanding of the difference, without learning the details: a function body defines a new scope. So, defining the function (by lambda
or def
) inside that function means your closure is from that new scope.
Upvotes: 2