Wednesday, July 3, 2019

Python lambda

A lambda function in python allows you to write a reusable expression. Unlike saving the result of an expression in a variable the expression is re-evaluated every time it is used.The simplest lambda function in python takes no arguments and simply returns a literal like the one below:

x = lambda : 100
print(x())
Notice that when x is declared with the lambda keyword it has to be called by using parenthesis.

The above example isn't anymore useful then just assigning x the value of 100. However, the benefit of using lambdas over variables is they are dynamic. That is they will always evaluate to the expression instead of the last value entered.

The lambda expression is a little easier for most people to understand because it works like you would expect a + b to behave in a mathematical equation.


a = 100
b = 1
x = lambda : a + b

print(x())

a = 10
b = 10
print(x())
We don't have to reassign x because a and b are re-evaluated on every call

Output:
101
20

In the above example I don't have to re-assign x like I would with a variable because it always re-evaluates the value of a and b before giving a result. A lambda function in python must return a value. They are intended to evaluate mathematical expressions and calling functions that return a value. However, because many functions return a value but otherwise do not produce a usable value lambdas are often used for non-expression calls. Python's print function, for example, returns None. Because it returns a value it can be used in a lambda as if it where an expression:


print_me = lambda : print("Hello World")
print_me()

Python lambdas can take zero or more arguments and don't need to be assigned to a variable. They are often passed into functions so that a named function doesn't have to be declared. This is often used when a function takes another function as a parameter.


lst = [1, 2, 2, 2]
my_map = map(lambda x : x * 2, lst)
print(list(my_map))

The map function, shown above, is a common use case of a lambda. It applies the expression passed as a lambda to the second argument which is a list of values and applies the expression to the list. Because the above function, x * 2, doesn't have to be named lambda is often referred to as an anonymous function.

The most common usage of the lambda is for callbacks. Callbacks are often used in User Interface libraries in order to perform an action on click.


MyButton = UIButton("Click Me")
MyButton.OnClick(lambda sender, state : print("You clicked me!"))

There is another way to accomplish the above expression using function definitions. It is a little extra syntax because you have to use the keyword return in order to actually have x() actually return a value. It also has to have a name which makes function definitions not very anonymous.

a = 10
b = 10
def x(): return a + b
print(x())
Still very compact but needs a name and a return value

Lambdas allow you to write python code in a functional style rather than object oriented or procedural. Python has an advantage over purely functional languages, that make it difficult to do things like save states or perform loops in that you can solve things that make sense with functional features and still write procedural or object oriented code.


I use the term procedural programming a little lightly. I think the term is still accurate as to how many programs are written today. However, its usage has dropped in popularity and is often replaced by the term sequential programming. Procedural code is usually in reference to older or "legacy" code.




Example - global keyword

You can declare a global variable in python easily enough but when you try to change it from a function no error is displayed and the old value is still there.

#declare a global variable
a = 23

def print_a_variable():
    print(a) #Printing it works just fine


def change_a_variable():
    a = 100000
    print(a) #seems to work but a is actually a new variable


print_a_variable()
change_a_variable()
print(a)

Output:
23
100000
23

If you use the keyword global in your function then the global is no longer read-only.


#declare a global variable
a = 23

def print_a_variable():
    #global a - not needed here because we can have readonly access to globals
    print(a) #Printing a works just fine


def change_a_variable():
    global a #If you want to change the global then it has to be declared here
    a = 100000
    print(a) #a is declared local and doesn't effect the global variable a


print_a_variable()
change_a_variable()
print(a) #a is still 23

Output:
23
100000
100000

nonlocal keyword

The nonlocal keyword is used to allow an inner function to access variables defined in an outer function. Without using the nonlocal keywo...