Parallel Python

Part 1: Anonymous Functions (lambda)

You have seen how functional programming allows you to write functions that can be used for mapping and reducing data. However, to date, this hasn’t saved you from typing much code. This is because you have had to declare every function that you want to use, i.e. you had to use syntax such as:

In [1]:
def add(x, y):
    return x + y

to both provide the code to the function (return x + y) and also to assign that function to an initial variable (add).

Anonymous functions (also called lambdas) allow you to declare the code for functions without having to assign them to a variable. They are used for short, one-line functions, such as the add function used above:

In [2]:
a = [1, 2, 3, 4, 5]
b = [6, 7, 8, 9, 10]

total = map(lambda x, y: x + y, a, b)

print(list(total))
[7, 9, 11, 13, 15]

This code has used lambda to create an anonymous function that is passed as an argument to map. The format of lambda is:

lambda arguments: expression

where arguments is a comma separated list of arguments to the function, and expression is a single line of code. Note that this function will automatically return the result of this single line of code.

Anonymous lambda functions are just like any other function. The only difference is that they have been created without being initially assigned to a variable. The unnamed function object created using

lambda arguments: expression

is completely identical to

def name(arguments):
    return expression

except that the def version assigns this function object to a variable called name, while the lambda version creates the function object without assigning it to a variable.

You use lambda whenever you want to pass a simple, one-line expression as an argument:

In [3]:
from functools import reduce

a = [1, 2, 3, 4, 5]

product = reduce(lambda x, y: x * y, a)

print(product)
120
In [4]:
squares = map(lambda x: x * x, a)

print(list(squares))
[1, 4, 9, 16, 25]

Binding Arguments

As well as using lambda to create functions as arguments, you can also use lambda to more quickly create simple functions:

In [5]:
square = lambda x: x * x

print(square(5))
25

Here you have created a simple function that accepts one argument, and returns that argument squared. You have immediately assigned this function to the variable square, allowing you to call this function via this variable.

With lambda, you are limited to using this to create functions that have only a single expression (i.e. single line of code). However, this single expression can include a call to another function. This can allow you to quickly create specialised versions of more generic functions by binding their arguments:

In [6]:
def add(x, y):
    """Return the sum of the two arguments"""
    return x + y

plus_five = lambda x: add(x, 5)

print(plus_five(7))
12

Here, we have created a new function that takes a single argument (x), and that only calls the function add with arguments x and 5. This is assigned to the variable plus_five. This means that plus_five is now a function that takes a single argument, and returns the result of adding five to that argument.

In this example, we have used lambda to bind the value of the second argument of add to the number 5. The use of lambda has reduced the amount of code needed to create the plus_five function. Compare this to what is needed if we didn’t use lambda:

In [7]:
def plus_five(x):
    return add(x, 5)

print(plus_five(7))
12

The saving is more useful when we want to create specialised functions for mapping or reduction:

In [8]:
def multiply(x, y):
    """Return the product of the two arguments"""
    return x * y

a = [1, 2, 3, 4, 5]

double_a = map(lambda x: multiply(x, 2), a)

print(list(double_a))
[2, 4, 6, 8, 10]

Exercise

Rewrite your countlines.py script so that it uses lambda instead of any defined function (e.g. you should replace the count_lines function).

If you get stuck or want some inspiration, a possible answer is given here.