Can a Lambda Function Call Itself Recursively in Python

Can a lambda function call itself recursively in Python?

The only way I can think of to do this amounts to giving the function a name:

fact = lambda x: 1 if x == 0 else x * fact(x-1)

or alternately, for earlier versions of python:

fact = lambda x: x == 0 and 1 or x * fact(x-1)

Update: using the ideas from the other answers, I was able to wedge the factorial function into a single unnamed lambda:

>>> map(lambda n: (lambda f, *a: f(f, *a))(lambda rec, n: 1 if n == 0 else n*rec(rec, n-1), n), range(10))
[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]

So it's possible, but not really recommended!

How can I prevent a lambda function from calling itself recursively?

You could use some indirection

func2 = (lambda f1, f2: lambda x: f1(x) + f2(x))(func1, func2)

so then

>>> func2(1)
5

This is a bit silly though - the short story is you need another function.

Python - can function call itself without explicitly using name?

I found a simple, working solution.

from functools import wraps

def recfun(f):
@wraps(f)
def _f(*a, **kwa): return f(_f, *a, **kwa)
return _f

@recfun
# it's a decorator, so a separate class+method don't need to be defined
# for each function and the class does not need to be instantiated,
# as with Alex Hall's answer
def fact(self, n):
if n > 0:
return n * self(n-1) # doesn't need to be self(self, n-1),
# as with lkraider's answer
else:
return 1

print(fact(10)) # works, as opposed to dursk's answer

How does this Python Lambda recursion expression work?

It may help to think of a function call as an operator. Because that's what it is. When you do rec_fn() you are doing two things. First, you're getting a reference to the object named rec_fn. This happens to be a function, but that doesn't matter (in Python, objects besides functions are callable). Then there is () which means "call the object I just named." It is possible to get a reference to a function without calling it, just by leaving off the parentheses, and then you can assign it different names, any of which can then be used to call it by adding the parentheses.

def func1():
print "func1"

func2 = func1

func2() # prints "func1"

Now you can see how the lambda works.

func3 = lambda x: x+1

You are doing the same as the func2 = func1 line above, except the lambda expression is the function. The syntax is just different; the lambda function can be defined without giving it a name.

Lambdas can have any number of parameters, so lambda: 3 is a function that takes no parameters and always returns 3, while lambda x, y: x+y is a function that takes two parameters and returns their sum.

As to the way or is being used, it's taking advantage of short-circuiting. Basically, or knows that if its first operand is True, it doesn't need to evaluate the second, because the result is going to be True regardless of what the second argument is. You could thus read this as if not 10==11: rec_fn(). By the way, and also short-circuits, although it does so if the first argument is False since it knows that the result will be False regardless of what the second argument is.

Lambda recursion over list in Python

recur = lambda l:len(l) if not isinstance(l,(tuple,list)) else sum(map(recur,l))

I think would work

or even cooler (self refering lambda :))

def myself (*args, **kw):
caller_frame = currentframe(1)
code = caller_frame.f_code
return FunctionType(code, caller_frame.f_globals)(*args,**kw)

print (lambda l:len(l) if not isinstance(l,(tuple,list)) else sum(map(myself,l)))(some_list)

or hyperboreus solution

lambda a:(lambda f, a: f(f, a))(lambda f, a:len(a) if not isinstance(a,(tuple,list)) else sum(f(f,e) for e in a), a)

which is whats known as a Y-Combinator ... which are nightmares to tell whats going on but they somehow work :P

Recursive AWS Lambda function calls - Best Practice

UPDATE: AWS EventBridge now looks like the preferred solution.


It's "Coupling" that I was thinking of, see here: https://www.jeffersonfrank.com/insights/aws-lambda-design-considerations

Coupling

Coupling goes beyond Lambda design considerations—it’s more about the system as a whole. Lambdas within a microservice are sometimes tightly coupled, but this is nothing to worry about as long as the data passed between Lambdas within their little black box of a microservice is not over-pure HTTP and isn’t synchronous.

Lambdas shouldn’t be directly coupled to one another in a Request Response fashion, but asynchronously. Consider the scenario when an S3 Event invokes a Lambda function, then that Lambda also needs to call another Lambda within that same microservice and so on.

aws lambda coupling

Sample Image

You might be tempted to implement direct coupling, like allowing Lambda 1 to use the AWS SDK to call Lambda 2 and so on. This introduces some of the following problems:

  1. If Lambda 1 is invoking Lambda 2 synchronously, it needs to wait for the latter to be done first. Lambda 1 might not know that Lambda 2 also called Lambda 3 synchronously, and Lambda 1 may now need to wait for both Lambda 2 and 3 to finish successfully. Lambda 1 might timeout as it needs to wait for all the Lambdas to complete first, and you’re also paying for each Lambda while they wait.

  1. What if Lambda 3 has a concurrency limit set and is also called by another service? The call between Lambda 2 and 3 will fail until it has concurrency again. The error can be returned to all the way back to Lambda 1 but what does Lambda 1 then do with the error? It has to store that the S3 event was unsuccessful and that it needs to replay it.

This process can be redesigned to be event-driven: lambda coupling

Sample Image

Not only is this the solution to all the problems introduced by the direct coupling method, but it also provides a method of replaying the DLQ if an error occurred for each Lambda. No message will be lost or need to be stored externally, and the demand is decoupled from the processing.



Related Topics



Leave a reply



Submit