10.2. Functional Lambda
Lambda - Anonymous functions
When function is used once
When function is short
You don't need to name it (therefore anonymous)
In Python, a lambda expression is a small anonymous function that can have any number of arguments, but can only have one expression. It is also known as a lambda function or lambda form.
Lambda expressions are defined using the lambda
keyword, followed by the
function's arguments and a colon, and then the expression to be evaluated.
The result of the expression is returned automatically.
Here's an example of a lambda expression that adds two numbers:
>>> add = lambda x, y: x + y
>>>
>>> result = add(2, 3)
>>>
>>> print(result)
5
In this example, the lambda
keyword is used to define a function that
takes two arguments (x
and y
) and returns their sum. The function
is assigned to the variable add
. The add()
function is then called
with the arguments 2
and 3
, and the result is stored in the variable
result
.
Lambda expressions are often used as a shortcut for defining small,
one-off functions that are only needed in a specific context. They can be
used anywhere that a function is expected, such as in the map()
and
filter()
functions.
- lambda
Anonymous function
Syntax:
lambda <arguments>: <expression>
Example:
>>> lambda x: x+1
<function <lambda> at 0x...>
Lambda Expressions:
>>> a = lambda x: x+1
>>> b = lambda x,y: x+y
Equivalent functions:
>>> def a(x):
... return x+1
>>> def b(x,y):
... return x+y
10.2.1. Problem
>>> def square(x):
... return x ** 2
>>>
>>> data = (1, 2, 3, 4)
>>> result = map(square, data)
>>>
>>> print(tuple(result))
(1, 4, 9, 16)
10.2.2. Solution
>>> data = (1, 2, 3, 4)
>>>
>>> result = map(lambda x: x**2, data)
>>> tuple(result)
(1, 4, 9, 16)
10.2.3. Mapping
>>> data = (1, 2, 3, 4)
>>>
>>> result = map(lambda x: x**2, data)
>>> tuple(result)
(1, 4, 9, 16)
10.2.4. Filtering
Even numbers
>>> data = (1, 2, 3, 4)
>>>
>>> result = filter(lambda x: x%2==0, data)
>>> tuple(result)
(2, 4)
10.2.5. One Argument
Regular function:
>>> def square(x):
... return x ** 2
Lambda:
>>> square = lambda x: x**2
10.2.6. Many Arguments
Regular function:
>>> def add(x, y):
... return x + y
Lambda:
>>> add = lambda x,y: x+y
10.2.7. Args and Kwargs
Regular function:
>>> def total(a, b, *args, **kwargs):
... return a + b + sum(args) + sum(kwargs.values())
Lambda:
>>> total = lambda a,b,*args,**kwargs: a+b+sum(args)+sum(kwargs.values())
Usage:
>>> total(1, 2, 3, 4, 5, 6, x=10, y=20)
51
10.2.8. Noop
>>> noop = lambda x: x
>>> def apply(data, fn=lambda x: x):
... return tuple(map(fn, data))
>>>
>>> data = (1, 2, 3, 4)
>>>
>>> apply(data)
(1, 2, 3, 4)
>>>
>>> apply(data, lambda x:x**2)
(1, 4, 9, 16)
10.2.9. Performance
Date: 2024-12-16
Python: 3.13.1
IPython: 8.30.0
System: macOS 15.2
Computer: MacBook M3 Max
CPU: 16 cores (12 performance and 4 efficiency) / 3nm
RAM: 128 GB RAM LPDDR5
>>> data = tuple(range(0,100))
>>>
>>> # doctest: +SKIP
... %%timeit -r 1000 -n 1000
... tuple(map(lambda x: x+1, data))
...
2.52 μs ± 87.3 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.49 μs ± 81 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.49 μs ± 86.1 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.49 μs ± 108 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.5 μs ± 109 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.49 μs ± 86.9 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
>>> data = tuple(range(0,100))
>>>
>>> # doctest: +SKIP
... %%timeit -r 1000 -n 1000
... def increment(x):
... return x + 1
... tuple(map(increment, data))
...
2.52 μs ± 77.4 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.53 μs ± 106 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.54 μs ± 109 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.51 μs ± 116 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.53 μs ± 125 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
>>> data = tuple(range(0,100))
>>>
>>> def increment(x):
... return x + 1
>>>
>>> # doctest: +SKIP
... %%timeit -r 1000 -n 1000
... tuple(map(increment, data))
...
2.46 μs ± 77.8 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.46 μs ± 73.5 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.48 μs ± 102 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.48 μs ± 114 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.48 μs ± 74.4 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
2.47 μs ± 72.3 ns per loop (mean ± std. dev. of 1000 runs, 1,000 loops each)
10.2.10. Note to Programmers of Different Languages
var result = Query("SELECT * FROM users")
.stream()
.filter(x -> x % 2 == 0)
.map(x -> x ** 2)
.map(x -> x + 1)
.map(x -> x + 10)
.collect(Collectors.toList());
>>> class Stream:
... def __init__(self, values):
... self.values = values
...
... def filter(self, fn):
... self.values = filter(fn, self.values)
... return self
...
... def map(self, fn):
... self.values = map(fn, self.values)
... return self
>>>
>>>
>>> DATA = (1, 2, 3, 4, 5, 6, 7, 8, 9)
>>>
>>> result = (
... Stream(DATA)
... .filter(lambda x: x % 2 == 0)
... .map(lambda x: x ** 2)
... .map(lambda x: x + 1)
... .map(lambda x: x + 10)
... )
>>> tuple(result.values)
(15, 27, 47, 75)
10.2.11. Convention
Usually parameters are named
x
andy
Usually there are no spaces in lambda expressions (to make code shorter)
"Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier" (PEP 8 -- Style Guide for Python Code)
Do not assign
lambda
to variableLambda is anonymous function and it should stay anonymous. Do not name it
Good:
>>> def square(x):
... return x**2
...
>>> square(4)
16
Maybe:
>>> def square(x): return x**2
>>> square(4)
16
Bad:
>>> square = lambda x: x**2
>>> square(4)
16
10.2.12. Use Case - 1
>>> data = [1, 2, 3, 4]
>>>
>>> result = map(lambda x: x**2, data)
>>> list(result)
[1, 4, 9, 16]
10.2.13. Use Case - 2
>>> PL = {'ą': 'a', 'ć': 'c', 'ę': 'e',
... 'ł': 'l', 'ń': 'n', 'ó': 'o',
... 'ś': 's', 'ż': 'z', 'ź': 'z'}
>>>
>>> text = 'zażółć gęślą jaźń'
>>>
>>>
>>> result = map(lambda x: PL.get(x,x), text)
>>> ''.join(result)
'zazolc gesla jazn'
10.2.14. Use Case - 3
>>> people = [
... {'age': 21, 'name': 'Mark Watney'},
... {'age': 25, 'name': 'Melissa Lewis'},
... {'age': 18, 'name': 'Rick Martinez'},
... ]
>>>
>>>
>>> result = filter(lambda x: x['age'] >= 21, people)
>>> list(result)
[{'age': 21, 'name': 'Mark Watney'},
{'age': 25, 'name': 'Melissa Lewis'}]
10.2.15. Use Case - 4
>>> people = [
... {'is_staff': True, 'name': 'Mark Watney'},
... {'is_staff': False, 'name': 'Melissa Lewis'},
... {'is_staff': True, 'name': 'Rick Martinez'},
... ]
>>>
>>>
>>> can_login = filter(lambda x: x['is_staff'], people)
>>> list(can_login)
[{'is_staff': True, 'name': 'Mark Watney'},
{'is_staff': True, 'name': 'Rick Martinez'}]
10.2.16. Use Case - 5
>>> users = [
... 'mwatney',
... 'mlewis',
... 'rmartinez',
... 'avogel',
... 'bjohanssen',
... 'cbeck',
... ]
>>>
>>> staff = [
... 'mwatney',
... 'mlewis',
... 'ptwardowski',
... 'jjimenez',
... ]
>>>
>>>
>>> can_login = filter(staff.__contains__, users)
>>> list(can_login)
['mwatney', 'mlewis']
10.2.17. Use Case - 6
>>> from urllib.request import urlopen
>>>
>>> def fetch(url: str,
... on_success = lambda result: result,
... on_error = lambda error: error,
... ) -> None:
... try:
... result = urlopen(url).read()
... except Exception as error:
... return on_error(error)
... else:
... return on_success(result)
>>>
>>>
... fetch(
... url = 'https://python3.info',
... on_success = lambda result: print(result),
... on_error = lambda error: print(error))
10.2.18. Further Reading
10.2.19. Assignments
# FIXME: zmienić by nie było inlajnowania
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: Functional Lambda Chain
# - Difficulty: easy
# - Lines: 2
# - Minutes: 2
# %% English
# 1. Inline functions `odd()` and `cube()` with `lambda` expressions
# 2. Run doctests - all must succeed
# %% Polish
# 1. Zastąp funkcje `odd()` i `cube()` wyrażeniami `lambda`
# 2. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `mean = sum(...) / len(...)`
# - type cast to `list()` before calculating mean to expand generator
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 9), \
'Python 3.9+ required'
>>> type(result) is float
True
>>> result
245.0
"""
def odd(x):
return x % 2
def cube(x):
return x ** 3
# Inline lambda expressions
# type: float
result = range(0,10)
result = filter(odd, result)
result = map(cube, result)
result = list(result)
result = sum(result) / len(result)