Lambda functions in Python


Reading time: 30 minutes

In Python, anonymous function is a function that is defined without a name. While normal functions are defined using the def keyword, in Python anonymous functions are defined using the lambda keyword. Hence, anonymous functions are also called lambda functions.

In more simple terms, the lambda keyword also called lambda operator in Python provides a shortcut for declaring small anonymous functions. Lambda functions behave just like regular functions declared with the def keyword. They can be used whenever function objects are required.

The following are the characteristics of Python lambda functions:

  • A lambda function can take any number of arguments, but they contain only a single expression. An expression is a piece of code executed by the lambda function, which may or may not return any value.
  • Lambda functions can be used to return function objects.
  • Syntactically, lambda functions are restricted to only a single expression.
  • The body of lambda functions is very small as it consists of only one expression.
  • The result of the expression is the value when the lambda is applied to an argument.
  • There is no need for any return statement in lambda function.

Syntax of Lambda Function

     lambda arguments: expression

Example-1 :

A lambda function that adds 10 to the number passed in as an argument, and print the result:

     x = lambda a : a + 10
     print(x(5))

Output :

     15

Lambda functions can take any number of arguments lets see by following example :

Example-2 :

A lambda function that multiplies argument a with argument b and print the result:

    x = lambda a, b : a * b
    print(x(5, 6))

Output :

    30

Example-3 :

A lambda function that sums argument a, b, and c and print the result:

    x = lambda a, b, c : a + b + c
    print(x(5, 6, 2))    

Output :

    13

normal def defined function VS lambda function.

This following program returns the cube of a given value:

    def cube(y): 
        return y*y*y; 

    g = lambda x: x*x*x 
    print(g(7)) 

    print(cube(5)) 

Output :

    343
    125

Without using Lambda :

Here, both of them returns the cube of a given number. But, while using def, we needed to define a function with a name cube and needed to pass a value to it. After execution, we also needed to return the result from where the function was called using the return keyword.

Using Lambda :

Lambda definition does not include a return statement, it always contains an expression which is returned. We can also put a lambda definition anywhere a function is expected, and we don’t have to assign it to a variable at all. This is the simplicity of lambda functions.

Why Use Lambda Functions?

Lambda functions are used when you need a function for a short period of time. This is commonly used when you want to pass a function as an argument to higher-order functions, that is, functions that take other functions as their arguments.

The use of anonymous function inside another function is explained in the following example:

    def testfunc(num):  
        return lambda x : x * num

In the above example, we have a function that takes one argument, and the argument is to be multiplied with a number that is unknown. Let us demonstrate how to use the above function:

    def testfunc(num):  
        return lambda x : x * num

    result1 = testfunc(10)

    print(result1(9))  

Output :

    90  

In the above script, we use a lambda function to multiply the number we pass by 10. The same function can be used to multiply the number by 1000:

    def testfunc(num):  
      return lambda x : x * num

    result2 = testfunc(1000)
    print(result2(9))  

Output :

    9000  

It is possible for us to use the testfunc() function to define the above two lambda functions within a single program:

    def testfunc(num):  
        return lambda x : x * num

    result1 = testfunc(10)  
    result2 = testfunc(1000)

    print(result1(9))  
    print(result2(9))  

Output :

    90  
    9000  

Mostly lambda functions are passed as parameters to a function which expects a function objects as parameter like map, reduce, filter functions.

The map() Function :

Syntax :

    map(function_object, iterable1, iterable2,...)

map functions expects a function object and any number of iterables like list, dictionary, etc. It executes the function_object for each element in the sequence and returns a list of the elements modified by the function object.In more simple terms , the map() function basically maps every item in the input iterable to the corresponding item in the output iterable, according to the logic defined by the lambda function.

Example:

    numbers_list = [2, 6, 8, 10, 11, 4, 12, 7, 13, 17, 0, 3, 21]

    mapped_list = list(map(lambda num: num % 2, numbers_list))

    print(mapped_list)  

Output :

    [0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1]

In the script above, we have a list numbers_list, which consists of random numbers. We then call the map() function and pass it a lambda function as the argument. The lambda function calculates the remainder after dividing each number by 2. The result of the mapping is stored in a list named mapped_list. Finally, we print out the contents of the list.

The filter() Function :

The Python's filter() function takes a lambda function together with a list as the arguments. It has the following syntax:

    filter(object, iterable)  

The object here should be a lambda function which returns a boolean value. The object will be called for every item in the iterable to do the evaluation. The result is either a True or a False for every item. Note that the function can only take one iterable as the input.

A lambda function, along with the list to be evaluated, is passed to the filter() function. The filter() function returns a list of those elements that return True when evaluated by the lambda funtion.

Like map function, filter function also returns a list of element. Unlike map function filter function can only have one iterable as input.

Example :

    numbers_list = [2, 6, 8, 10, 11, 4, 12, 7, 13, 17, 0, 3, 21]

    filtered_list = list(filter(lambda num: (num > 7), numbers_list))

    print(filtered_list)  

Output :

    [8, 10, 11, 12, 13, 17, 21]

In the above example, we have created a list named numbers_list with a list of integers. We have created a lambda function to check for the integers that are greater than 7. This lambda function has been passed to the filter() function as the argument and the results from this filtering have been saved into a new list named filtered_list.

The reduce() Function :

The reduce() function in Python takes in a function and a list as argument. The function is called with a lambda function and a list and a new reduced result is returned. This performs a repetitive operation over the pairs of the list. This is a part of functools module.

Synatx :

     reduce(fun,seq) 

Working :

  • At first step, first two elements of sequence are picked and the result is obtained.
  • Next step is to apply the same function to the previously attained result and the number just succeeding the second element and the result is again stored.
  • This process continues till no more elements are left in the container.
  • The final returned result is returned and printed on console.

Example :

This following code illustrates reduce() with lambda() to get sum of a list :

    from functools import reduce
    li = [5, 8, 10, 20, 50, 100] 
    sum = reduce((lambda x, y: x + y), li) 
    print (sum) 

Output :

    193

Here the results of previous two elements are added to the next element and this goes on till the end of the list like (((((5+8)+10)+20)+50)+100).

Common uses of lambda expressions :

  1. Since lambda functions are anonymous and do not require a name to be assigned, they are usually used to call functions(or classes) which require a function object as an argument. Defining separate functions for such function arguments is of no use because, the function definition is usually short and they are required only once or twice in the code. For example, the key argument of the inbuilt function, sorted().
Example :

a. Program to show the use of normal function :-

    def Key(x): 
        return x%2
    nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
    sort = sorted(nums, key = Key) 
    print(sort) 

b. Program to show the use of lambda function :-

       nums = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
       sort_lambda = sorted(nums, key = lambda x: x%2) 
       print(sort_lambda) 
  1. Lambda functions are inline functions and hence they are used whenever there is a need of repetitive function calls to reduce execution time. Some of the examples of such scenarios are the functions: map(), filter() and sorted().

Pros and Cons of lambda functions :

Pros of lambda functions:

i. Being anonymous, lambda functions can be easily passed without being assigned to a variable.
ii. Lambda functions are inline functions and thus execute comparatively faster.
iii. Many times lambda functions make code much more readable by avoiding the logical jumps caused by function calls.
For example, read the following blocks of code.

program performing operation using def() :

    def fun(x, y, z): 
        return x*y+z 
    a = 1
    b = 2
    c = 3

    # logical jump 
    d = fun(a, b, c) 
    print(d)      

program performing operation using lambda :

    d = (lambda x, y, z: x*y+z)(1, 2, 3) 
    print(d)     

Cons on lambda functions:

i. Lambda functions can have only one expression.
ii. Lambda functions cannot have a docstring.
iii. Many times lambda functions make code difficult to read.
For example, see the blocks of code given below.

program performing operation using def() :

    def func(x): 
        if x == 1: 
            return "one"
        elif x == 2: 
            return "two"
        elif x == 3: 
            return "three"
        else: 
            return "ten"
    num = func(3) 
    print(num) 

program performing operation using lambda :

    num = (lambda x: "one" if x == 1 else( "two" if x == 2 
                           else ("three" if x == 3 else "ten")))(3) 
    print(num) 

Misuse of Lambda expressions :

  1. Assignment of lambda expressions :

The official python style guide PEP8, strongly discourages the assignment of lambda expressions as shown in the example below.

          func = lambda x, y, z: x*y + z

Instead, it is recommended to write a one-liner function as,

          def func(x, y, z): return x*y + z 

While the second method encourages the fact that lambda functions are anonymous, it is also useful for tracebacks during debugging.

  1. Wrapping lambda expressions around functions :
    Many times, lambda expressions are needlessly wrapped around functions as shown below.
        nums = [-2, -1, 0, 1, 2]
        sort = sorted(nums, key=lambda x: abs(x))

While the above syntax is absolutely correct, programmers must understand that all functions in python can be passed as function objects.
Hence the same code can(and should) be written as,

        sort = sorted(nums, key=abs)
  1. Passing functions unnecessarily :
    Many times, programmers pass functions which perform only a single operation.
    See the following code.
        nums = [1, 2, 3, 4, 5]
        summation = reduce(lambda x, y: x + y, nums)

The lambda function passed above performs only a single operation, adding the two arguments. The same result can be obtained by the using the built-in function sum, as shown below.

    nums = [1, 2, 3, 4, 5]
    summation = sum(nums)

Programmers should avoid using lambda expressions for common operations, because it is highly probable to have a built-in function providing the same results.

Overuse of lambda expressions :

  1. Using lambda for non-trivial functions :
    Sometimes, simple functions can be non-trivial. See the code below.
        details = [{'p':100, 'r':0.01, 'n':2, 't':4}, 
                   {'p':150, 'r':0.04, 'n':1, 't':5}, 
                   {'p':120, 'r':0.05, 'n':5, 't':2}]  
        sorted_details = sorted(details,  
                                key=lambda x: x['p']*((1 + x['r']/
                                        x['n'])**(x['n']*x['t']))) 
        print(sorted_details) 

Output:

    [{β€˜n’: 2, β€˜r’: 0.01, β€˜t’: 4, β€˜p’: 100}, {β€˜n’: 5, β€˜r’: 0.05, β€˜t’: 2, β€˜p’: 120}, {β€˜n’: 1, β€˜r’: 0.04, β€˜t’: 5, β€˜p’: 150}]   

Here, we are sorting the dictionaries on the basis of the compound interest.
Now, see the code written below, which uses def.

    details = [{'p':100, 'r':0.01, 'n':2, 't':4}, 
               {'p':150, 'r':0.04, 'n':1, 't':5}, 
               {'p':120, 'r':0.05, 'n':5, 't':2}]  
    def CI(det): 
        '''sort key: coumpound interest, P(1 + r/n)^(nt)'''
        return det['p']*((1 + det['r']/det['n'])**(det['n']*det['t'])) 
    sorted_details = sorted(details, key=CI) 
    print(sorted_details) 

Output:

    [{β€˜n’: 2, β€˜r’: 0.01, β€˜t’: 4, β€˜p’: 100}, {β€˜n’: 5, β€˜r’: 0.05, β€˜t’: 2, β€˜p’: 120}, {β€˜n’: 1, β€˜r’: 0.04, β€˜t’: 5, β€˜p’: 150}]

Though both codes do the same thing, the second one which uses def is much more readable. The expression written here under the lambda might be simple, but it has a meaning(formula for compound interest). Hence, the expression is non-trivial and deserves a name. Using lambda expressions for non-trivial functions reduces the readability of the code.

  1. Using lambdas when multiple lines would help :
    If using a multiple line function makes the code more readable, using lambda expressions to reduce some lines of code is not worth it.
    For example, see the code below :
        people = [(β€˜sam’, β€˜M’, 18), (β€˜susan’, β€˜F’, 22), (β€˜joy’, β€˜M’, 21), (β€˜lucy’, β€˜F’, 12)]
        sorted_people = sorted(people, key=lambda x: x[1])

Also see the following code which uses def.

    def Key(person):
        name, sex, age = person
        return sex
    sorted_people = sorted(people, key=Key)

See how tuple unpacking in the second block of code makes it much more readable and logical. Readibility of the code should the be utmost priority of a programmer, working in a collaborative environment.

  1. Using lambda expressions for map and filter :
    Lambdas are very commonly used with map() and filter().

  2. Use of higher order functions :
    The functions which accept other function objects as arguments are called higher order functions (i.e. map() and filter()), which are common in functional programming. As stated above, lambda expressions are commonly used as the function arguments of higher order functions. Compare the two code blocks shown below.
    Using high order function reduce()

        nums = [1, 2, 3, 4, 5]
        product = reduce(lambda x, y: x*y, nums, 1)

Without using high order function

        nums = [1, 2, 3, 4, 5]
        def multiply(nums):
            prod = 1
            for number in nums:
                prod *= number
            return prod
        product = multiply(nums)

While the first block uses fewer lines of code and is not that difficult to understand, programmers with no background of functional programming will find the second block of code much readable. Unless practicing proper functional programming paradigm, passing one function to another function is not appreciated, as it can reduce readability.