Lambda in Python
In the 1930s, mathematicians began to solve the problem of resolution—Entscheidungsproblem— which was first formulated by David Hilbert. The crux of the problem’s solution is the formal language the statement needs to be written in. The problem’s solution needs to prove the existence of an algorithm that determines a statement’s truth or falsity in a finite number of steps.
The answer was found by the great scientists of the time. Alonzo Church and Alan Turing showed the Entscheidungsproblem problem was generally unsolvable, as proved by Church with the help of the λ-calculus he invented in the mid-1930s and by Turing’s machine he created.
The modern Python language, which is now widely used in information systems development, machine learning, and system administration, also supports the use of lambda calculus.
Let's see how the lambda calculus works in Python and where it is appropriate to use this construction.
A simple example of Lambda in Python
Generally speaking, all lambda expressions in Python must have the following composition:
lambda arguments : expression
Here, lambda is a keyword, arguments can be one or several arguments, and the expression is some action to perform and return results to the upper code.
Let’s take a look at this classical example in Python:
import unittest def add_func(x, y): return x + y class TestFunction(unittest.TestCase): def test_func(self): self.assertEqual(add_func(2,3), 5) if __name__ == '__main__': unittest.main()
In this example, the function add_functhat accepts two arguments (2 and 3) and adds them together. As shown in unit tests, there are 5 as a successful sum of two given arguments.
Ran 1 test in 0.000s OK
How will this function work with lambda expression? The code is very simple.
This example uses sum = lambda x, y : x+y as the lambda expression instead of the function add_func(). To call this lambda, you can use sum(2,3). The result is the same as shown on the unit tests.
Ran 2 tests in 0.000s OK
Just in case, we’ll mention the type of lambda expression object type(sum) which will return <class 'function'>.
Please consider that Python’s style guide, PEP8, highly recommends that the use case def add_func() has a clear code understanding and readability.
As mentioned in PEP8, “Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier:
# Correct: def f(x): return 2*x # Wrong: f = lambda x: 2*x
The first form means that the name of the resulting function object is specifically 'f' instead of the generic '<lambda>'. This is more useful for tracebacks and string representations in general. The use of the assignment statement eliminates the sole benefit a lambda expression can offer over an explicit def statement (i.e. that it can be embedded inside a larger expression)”.
At the same time, the lambda expression is helpful in some parts of your code and will be understood very well.
Why use Lambda in Python
map() is a very familiar function in Python and it’s very helpful; for example, if you need to perform an action on every element, but do not use the cycle, lille for or while. Please take a look at its manual here.
map(function_object, iterable1, iterable2,...)
Where function_object is the object for function and iterable1, 2, is a set of iterable elements.
list(map(lambda x : x*2, [1, 2, 3, 4, 5]))
It will return a list:
[2, 4, 6, 8, 10]
Here, we use lambda x : x*2 as an anonymous function that makes syntax very compact, avoids defining the new function, and gives a clear understanding for everybody. The function list() is necessary because it returns a map object, so it will create a list from the iterator.
As well as map, the filer() function is a great example of how to express your idea in Python in a very compact and clear form. You can look at its description here.
Let’s find all numbers that are a fraction of 10.
numbers = [1, 20, 3, 40, 5, 60, 100] result = filter(lambda x: x % 10 == 0, numbers) print (list(result))
[20, 40, 60, 100]
Please consider that filter() constructs an iterator. To get a list from the iterator, you need to use something like list (result).
In addition, it’s important to mention that list comprehension can be effectively used for many tasks. This allows you to do many helpful actions on a list without the for instruction. Please refer to this article for more details.
The function functools.reduce() is a great example where the lambda expression is effectively used. Please take a look at its description here.
import functools result = functools.reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) print (result)
This will calculate the sum of the sequence ((((1+1)+2)+3)+5) and, in our case, will return 15 as a result.
Another great well-known example from many internet sources is the calculation of Fibonacci numbers:
fib = lambda n: functools.reduce(lambda x, _: x + [x[-1] + x[-2]], range(n - 2), [0, 1]) print (fib (10))
This will produce a list of Fibonacci numbers:
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
While it’s not simple to understand, it works very well. This lambda expression returns a list and the list starts from 0 and 1. Then, every next element is computed like xn = xn-1 + xn-2. This calculation repeats n-2 times.
In this example, reduce() accepts three parameters functools.reduce(function, iterable[, initializer]).
- function is lambda x, _: x + [x[-1] + x[-2]] i.e. xn = xn-1 + xn-2
- iterable is range(n-2) because we don’t need to calculate elements 0 and 1 in the Fibonacci sequence
- initialiser is [0, 1], i.e. is the start sequence of the Fibonacci number.
This interesting example uses two lambda expressions at the same time. It works fast, at least with the same speed as Python code without lambda.
Another great example of using lambda is sorted(). You can find a classical example from this manual.
class Student: def __init__(self, name, grade, age): self.name = name self.grade = grade self.age = age def __repr__(self): return repr((self.name, self.grade, self.age)) student_objects = [ Student('john', 'A', 15), Student('jane', 'B', 12), Student('dave', 'B', 10), ] sorted(student_objects, key=lambda student: student.age) # sort by age
We will have the following output:
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
The magic of using lambda is providing a comparison function lambda student: student.age.
Another great example of using lambda is the as __lt__() function which can be given directly to the Student object:
Student.__lt__ = lambda self, other: self.age < other.age sorted(student_objects)
It will give the following output:
[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]
This example shows how to use lambda effectively in Python.
Many Python developers from Svitla Systems recommend lambda as a very helpful element for real tasks in programming. With that being said, lambda needs to be used very carefully, according to the PEP8 recommendation.
If you’d like to learn more about using lambda in Python, please refer to this article from Real Python by Andre Burgaud where you’ll understand more about:
- Evaluation Time
- Monkey Patching
Many programming languages now support lambda. Some of the languages use this concept very intensively. For one, the Python language supports very rich possibilities to use lambda but the code needs to be clear, easy to read, and reasonable. Many new developers overuse lambda in Python, but this code should be replaced with def functions.
Our experienced Python developers and data scientists from Svitla Systems have a great level of understanding and practical expertise in creating large projects with different Python frameworks. If you need to develop your project on Python from scratch or rebuild an existing project, please contact Svitla Systems representatives in your area.
Let's meet Svitla
We look forward to sharing our expertise, consulting you about your product idea, or helping you find the right solution for an existing project.
Your message is received. Svitla's sales manager of your region will contact you to discuss how we could be helpful.