views:

129

answers:

5
rec_fn = lambda: 10==11 or rec_fn()
rec_fn()

I am new to Python and trying to understand how lambda expressions work. Can somebody explain how this recursion is working? I am able to understand that 10==11 will be 'false' and that's how rec_fn will be called again and again recursively.

But what I am not able to get is this seemingly new way of writing a lambda expression.

whatever happened to lambda x: x+y where there is a parameter 'x' going into the unnamed function?

Also, why is

rec_fn() = lambda: .... // a syntax error
rec_fn = lambda: .... //syntactically correct - WHY?

What is rec_fn? Is it a function or a variable?

A: 

A function invocation -- x() -- is an expression. It is lot a legal syntax construct on the left side of an assignment. What should happen? (It is roughly the same as saying 42 = lambda: ....)

In the 2nd case, you are simply assigning the new function object created (with the lambda keyword) to a variable (named rec_fn) and not invoking a function.

Perhaps a more clear way is to use the (preferred) non-lambda nested function approach:

# just for example, not really useful as it is unless you like to eat CPU
def rec_fn():
  return 10 == 11 or rec_fn()

rec_fn()

The lambda keyword is just a syntactic shortcut which can be used as part of an expression.

rec_fn is a local variable in the above cases (assuming said code is nested in a function/method). The rec_fn variable stores a function object which can later be invoked with (). Methods are roughly the same (functions which can be invoked), but they are properties and not variables.

pst
A: 
  rec_fn = lambda: 10==11 or rec_fn()
  rec_fn()

is the similar to this expression, however this one requires a parameter,

rec_fn = lambda x: 10==11 or rec_fn(x)
x = ...
rec_fn(x)

whereas you'r rec_fn() with you're calling a function with no parameters hence no x

rec_fn() = lambda: .... // a syntax error

This is trying to set result of the function call rec_fn() (a right had side expression) to a value. There is no variabele there to assign the lambda function to.

rec_fn = lambda: .... //syntactically correct - WHY?

here rec_fn in the variable that holds the lambda (in essence like a function pointer)

Preet Sangha
A: 
rec_fn = lambda: 10==11 or rec_fn()
rec_fn()

The body of a function is not evaluated until it is executed. At the start, rec_fn has no value. The contents of the lambda is just some expression that has some function call on some variable rec_fn. It won't fail yet because the function isn't executed yet. The new lambda function is then assigned to the variable rec_fn followed by a call to the function. Now since the function is being executed, it will go through the motions up to the function call. The expression is 10==11 or rec_fn(). It's an or expresison so the left hand side is evaluated. 10==11 is False so it must evaluate the right hand side which is a function call to some function (or other callable object) rec_fn. At that point, rec_fn is assigned to the function we just created (itself) so it gets called (recursively). And so on. It is equivalent to:

def rec_fn():
    return 10==11 or rec_fn()

Lambdas can be written using as many parameters as necessary. In the case of lambda: ..., there are none specified so it's a "function that takes no arguments."

Just remember, functions (and by extension, lambdas) are first class objects. You can pass them around like any other object and store them into other variables.

rec_fn = lambda: ...

is fine because you've defined a lambda function and stored it into the variable rec_fn. It can be called by using that name rec_fn() like you would any other function.

rec_fn() = lambda: ...

on the other hand fails because you cannot assign anything to the result of the function call rec_fn().

Defining a function this way is much different than a normal function definition:

def rec_fn2(): # here you may use the parens with the name to indicate it takes no arguments
    ...        # unlike in the lambda assignment above

Just try to remember the difference.

Jeff M
+1  A: 

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.

kindall
A: 

This is maybe more understandable example of recursion, factorial lambda version:

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

Output:

3628800

Be aware of Python's recursion limit, though.

Example of using or as this if..else:

print 1 or 'a'
print 'a' or False
print False or True or 0/9
fact_or = lambda x: x == 0 and 1 or x * fact_or(x-1)
print fact_or(10)
Tony Veijalainen
Yeah, this one is definitely more understandable. Clear "if/else" statements. But using "or" is much more succinct. Somehow, it's not very intuitive.
Deepak
Using `i` or `l` for variable name are also succint, and sometimes I use them sometimes in hurry or out of old habbit. Often I also regret that afterwards.
Tony Veijalainen