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
>>> 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. Syntax¶
lambda <arguments>: <expression>
10.2.2. Convention¶
Usually parameters are named
x
andy
Use shortest code possible
Do not assign
lambda
to variableLambda is anonymous function and it should stay anonymous. Do not name it
PEP 8 -- Style Guide for Python Code: "Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier". Lambda is anonymous function and it should stay anonymous. Do not name it.
Usually there are no spaces in lambda expressions (to make code shorter)
Bad:
>>> square = lambda x: x**2
>>> square(4)
16
Good:
>>> def square(x):
... return x**2
...
>>> square(4)
16
PEP 8 -- Style Guide for Python Code: "Always use a def statement instead of an assignment statement that binds a lambda expression directly to an identifier":
10.2.3. Note to Programmers of Different Languages¶
query = 'SELECT * FROM users'
result = database(query).stream()
.filter(user -> user.age > 5)
.filter(user -> user.firstname == 'Mark')
.filter((x,y) -> x + y)
.collect(Collectors.toList());
10.2.4. Noop¶
>>> noop = lambda: ...
>>> def request(on_error = lambda: ...):
... ...
10.2.5. Lambda with Map¶
Increment:
>>> data = [1, 2, 3, 4]
>>>
>>> result = map(lambda x: x+1, data)
>>> list(result)
[2, 3, 4, 5]
10.2.6. Lambda with Filter¶
Even numbers:
>>> DATA = [1, 2, 3, 4]
>>>
>>> result = filter(lambda x: x%2==0, DATA)
>>> list(result)
[2, 4]
10.2.7. Performance¶
Python 3.11.5
>>> %%timeit -r 1000 -n 10_000
... def increment(x):
... return x + 1
... map(increment, range(0,100))
271 ns ± 30.6 ns per loop (mean ± std. dev. of 1000 runs, 10000 loops each)
>>> %%timeit -r 1000 -n 10_000
... map(lambda x: x+1, range(0,100))
262 ns ± 29 ns per loop (mean ± std. dev. of 1000 runs, 10000 loops each)
>>> %%timeit -r 1000 -n 1000
... def increment(x):
... return x + 1
... list(map(increment, range(0,100)))
7.48 µs ± 608 ns per loop (mean ± std. dev. of 1000 runs, 1000 loops each)
>>> %%timeit -r 1000 -n 1000
... list(map(lambda x: x+1, range(0,100)))
7.36 µs ± 545 ns per loop (mean ± std. dev. of 1000 runs, 1000 loops each)
10.2.8. Advanced With Args and Kwargs¶
>>> total = lambda a,b,*args,**kwargs: a+b+sum(args)+sum(kwargs.values())
>>> total(1,2,3,4,5,6,x=10,y=20)
51
10.2.9. Use Case - 0x01¶
>>> data = [1, 2, 3, 4]
>>>
>>> result = map(lambda x: x**2, data)
>>> list(result)
[1, 4, 9, 16]
10.2.10. Use Case - 0x02¶
>>> 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.11. Use Case - 0x03¶
>>> 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.12. Use Case - 0x04¶
>>> 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.13. Use Case - 0x05¶
>>> 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.14. Use Case - 0x06¶
>>> from urllib.request import urlopen
>>>
>>> def fetch(url: str,
... on_success = lambda result: ...,
... on_error = lambda 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.15. Use Case - 0x07¶
>>> class Apply:
... 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 = (
... Apply(DATA)
... .filter(lambda x: x % 2 == 0)
... .map(lambda x: x ** 2)
... .map(lambda x: x + 1)
... .map(lambda x: x + 10)
... )
>>> list(result.values)
[15, 27, 47, 75]
10.2.16. Further Reading¶
10.2.17. Assignments¶
"""
* Assignment: Functional Lambda Chain
* Type: class assignment
* Complexity: easy
* Lines of code: 2 lines
* Time: 3 min
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
>>> 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)