Learn how to use Lambda Function in Python
Lambda in Python is an anonymous function, the syntax is tighter and more concise than a regular function.
With this article, we will learn:
- What is Lambda like
- How is the Lambda and the normal function different?
- How to write a lambda function
- The functions in the library use lambda
- When to use or avoid lambda
The article is translated from source: https://realpython.com/python-lambda/#anonymous-functions
The content of the article is tested on Python 3.6.
Lambda Calculus (Lambda Calculus)
The Lambda expression in python or other languages is derived from the lambda calculation, a calculation method discovered by Alozo Church. In this section, you will see when lambda was introduced and why it is a fundamental concept in the Python ecosystem.
History
Alozo Church proposed lambda calculus, a language based on abstraction in 1930. Lambda calculus can encode any calculation. It is Turing complete but contrary to the concept of the Turing machine, it is in pure form and does not hold any state.
Functional languages have roots in mathematical logic and lambda arithmetic, functional languages based on state computation models invented by Alan Turning. The two computational models, the lambda calculation and the Turning machine, can be translated back and forth. This correlation is called the Church-Turing theory.
The functional language directly inherits the lambda itnhs philosophy, adopting a programming approach that emphasizes abstraction, data transformation, composition, and pureity (no state and no side effect). . Examples of functional languages are Haskell, Lisp, and Erlang
Turning Machine, in contrast, leads to programming in languages such as Fortna, C, and Python
Programming style with statements, control the program flow step by step. This approach modulates mutation and requires state management.
Python certainly didn’t inherit functional language, but it adopted a number of functional concepts early on. In January 1994, map()
, filter()
, reduce()
and lambda operator were added to the language.
First example
Here are a few examples of style functionalities in Python:
A function is defined using keyword def
:
1 2 3 | def indentity(x): return x |
indentity()
takes an x parameter and returns it as an argument
on the other hand, if using Lambda Python, you would write the following:
1 2 | lambda x: x |
In the above example, the expression is generated tuwf:
- Keyword: lambda
- Constraint variable: x
- Body: x
Note: In this post, a bound variable is an argument to the lambda function. Although, an unbound free variable can be referenced in the body of the expression. A free variable can be a row of numbers or is known to be defined within the function.
You can add a comment, a function that returns the value plus one:
1 2 | lambda x: x + 1 |
You can use the above function with an argument by enclosing the function and its arguments with parentheses:
1 2 | (lambda x: x + 1)(2) |
Below is a detailed explanation of lambda.
1 2 3 4 | (lambda x: x + 1)(2) = lambda 2: 2 + 1 = 2 + 1 = 3 |
Because the lambda function is an expression, there is a name for it.
1 2 3 4 | >>> add_one = lambda x: x + 1 >>> add_one(2) 3 |
The above expression corresponds to this spelling:
1 2 3 | def add_one(x): return x + 1 |
All of these functions take a single argument. You may have noticed that, in the definition of lambdas, the arguments don’t have parentheses around them. Multi-argument functions are represented in Python lambdas by enumerating arguments and separating them with commas (,) but not enclosing them with parentheses:
1 2 3 4 | >>> full_name = lambda first, last: f'Full name: {first.title()} {last.title()}' >>> full_name('guido', 'van rossum') 'Full name: Guido Van Rossum' |
The Lambda function assigned to full_name
takes 2 arguments and returns a string containing the last name and first name. As shown above, a lambda function doesn’t need parentheses, and calling the function is as simple as calling it regular.
Anonymous Function
The following words can be used interchangeably depending on the language:
- Anonymous functions
- Lambda functions
- Lambda expressions
- Lambda abstractions
- Lambda form
- Function literals
But it basically just refers to anonymity. An anonymous function is a function that has no name. In Python, an anonymous function can be created with keyword lamda
. The example is not named but can basically be assigned to a variable. Below is an unnamed lambda that takes 2 arguments and returns the sum
1 2 | >>> lambda x, y: x + y |
To call it you use
1 2 3 | >>> _(1, 2) 3 |
The example above is leveraging the interactive interpreter-only feature provided via an underscore (). You cannot code similar in module.
Note: In the compiler, the lower quota is associated with the last expression executed. In the above example, _
points to the lambda function. For more details, please refer to the link
Additionally, a pattern that is implemented in other languages such as JS that instant function execution is also applied to Lambda. This is called an Immediately Invoked Function Expression (IIFE, pronounced “iffy”). Here is an example:
1 2 3 | >>> (lambda x, y: x + y)(2, 3) 5 |
The Lambda function is defined above and is real when with 2 arguments passed. It returns a total value of 5. Python discourages the use of lambda expressions of this type. It is simply the result of a callable lambda expression, unlike the body of an ordinary function. Lambda functions are commonly used with higher order functions, which take one or more functions as arguments, or return one or more functions. A lambda function can be a higher order function by taking a function (normal or lambda) as an argument like in the following example:
1 2 3 4 5 6 | >>> high_ord_func = lambda x, func: x + func(x) >>> high_ord_func(2, lambda x: x * x) 6 >>> high_ord_func(2, lambda x: x + 3) 7 |
Python has built-in HOFs in standard libraries like map()
, filter()
etc … and you can use the lambda function in it.
Python Lambda and Pure Function
From this quote the Python Design and History FAQ we can see in general regarding the use of lambda functions in Python:
Unlike lambda from – where we add functions in other languages, Python lambda is just a shorthand if you’re too lazy to write a function.
However, don’t let this statement prevent you from using the lambda function. The following paragraphs will show the common ground and the understanding between lambda and regular function.
Function
You may be wondering what distinguishes a lambda function when assigned to a variable and a regular function, sensitively nothing. Let’s take a look at Python in a look at a function built with a retủn
statement and a function built in lambda:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> import dis >>> add = lambda x, y: x + y >>> type(add) <class 'function'> >>> dis.dis(add) 1 0 LOAD_FAST 0 (x) 2 LOAD_FAST 1 (y) 4 BINARY_ADD 6 RETURN_VALUE >>> add <function <lambda> at 0x7f30c6ce9ea0> |
dis
is the module that parses the Python bytecode code generated by the Python compiler
You can see that dis()
displayed in Python bytecode that allows you to check the low-level instructions that the Python interpreter will use during program execution.
Now let’s return the value with a regular function:
1 2 3 4 5 6 7 8 9 10 11 12 | >>> import dis >>> def add(x, y): return x + y >>> type(add) <class 'function'> >>> dis.dis(add) 1 0 LOAD_FAST 0 (x) 2 LOAD_FAST 1 (y) 4 BINARY_ADD 6 RETURN_VALUE >>> add <function add at 0x7f30c6ce9f28> |
Looking at the two results, we can expect the same. But notice that naming is different: for a regular function, the function name will be add
and for a lambda function it’s just a lambda
.
Traceback
In the previous section, in the context of the lambda function, Python did not provide a name for that function, but displayed it as the lambda
. This may be a limitation that we need to consider when an exception occurs and a traceback will only show <lambda>
:
1 2 3 4 5 6 7 | >>> div_zero = lambda x: x / 0 >>> div_zero(2) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <lambda> ZeroDivisionError: division by zero |
Above is the traceback of the exception raised with the lambda function. And below is an example with a regular function
1 2 3 4 5 6 7 | >>> def div_zero(x): return x / 0 >>> div_zero(2) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in div_zero ZeroDivisionError: division by zero |
The normal function fires the same error but only leads to more precision because it provides the function name, div_zero.
Syntax
No Statements
A lambda function cannot contain any statements. In the lambda function, statements like return
, pass
, raise
will raise
a SyntaxError
error. Here’s an example where we add assert
inside the lambda:
1 2 3 4 5 6 | >>> (lambda x: assert x == 2)(2) File "<input>", line 1 (lambda x: assert x == 2)(2) ^ SyntaxError: invalid syntax |
This example tests x for a value of 2 or not. But the interpreter identifies a Syntax Error while parsing that involves the asser
statement in the body of the lambda.
Single Expression
As opposed to a regular function, a lambda function is just an expression. Although inside the body of a lambda, you can extend the expression across multiple lines using parentheses or a multi-line string, in short it still has only one expression:
1 2 3 4 | >>> (lambda x: ... (x % 2 and 'odd' or 'even'))(3) 'odd' |
The above example will return odd
if the argument is even and vice versa. It is written in two lines because we put it inside the parentheses, but it is actually still considered a single expression.
Type Annotations
If you are familiar with using Python built-in type hints, then you have an extra reason to prefer regular functions over lambda functions because lambda functions don’t support this.
1 2 3 | def full_name(first: str, last: str) -> str: return f'{first.title()} {last.title()}' |
Any type-related error with full_name () can be caught by tools like mypy
or pyre
, while with the lambda function banj chir get syntax errors:
1 2 3 4 5 6 | >>> lambda first: str, last: str: first.title() + " " + last.title() -> str File "<stdin>", line 1 lambda first: str, last: str: first.title() + " " + last.title() -> str SyntaxError: invalid syntax |
IIFE
Lambda functions have IIFEs while regular functions don’t. However, this feature may not be used in practice. Example of a lambda function IIFE.
1 2 3 | >>> (lambda x: x * x)(3) 9 |
Argument
Like normal functions, Lambda also allows passing arguments. The following example will show us that and a few ways to pass arguments.
1 2 3 4 5 6 7 8 9 10 11 12 13 | >>> (lambda x, y, z: x + y + z)(1, 2, 3) 6 >>> (lambda x, y, z=3: x + y + z)(1, 2) 6 >>> (lambda x, y, z=3: x + y + z)(1, y=2) 6 >>> (lambda *args: sum(args))(1,2,3) 6 >>> (lambda **kwargs: sum(kwargs.values()))(one=1, two=2, three=3) 6 >>> (lambda x, *, y=0, z=0: x + y + z)(1, y=2, z=3) 6 |
Decorator
In Python, a decorator is a pattern that allows you to add a behavior to a function or class. It is usually represented with @decorator
before a function.
1 2 3 4 5 6 7 8 9 10 | def some_decorator(f): def wraps(*args): print(f"Calling function '{f.__name__}'") return f(args) return wraps @some_decorator def decorated_function(x): print(f"With argument '{x}'") |
In the above example, the some_decorator
function is a function that adds a behavior to the decorated_function
function, so when you call the decorated_function("Python")
the result will be:
1 2 3 | Calling function 'decorated_function' With argument 'Python' |
decorated_function()
only prints With argument 'Python'
, but with decorator, it is added with another action of printing Calling function 'decorated_function'
.
A decorator can be applied to a lambda like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <span class="token comment"># Defining a decorator</span> <span class="token keyword">def</span> <span class="token function">trace</span> <span class="token punctuation">(</span> f <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">def</span> <span class="token function">wrap</span> <span class="token punctuation">(</span> <span class="token operator">*</span> args <span class="token punctuation">,</span> <span class="token operator">**</span> kwargs <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">print</span> <span class="token punctuation">(</span> <span class="token string-interpolation"><span class="token string">f"[TRACE] func: </span><span class="token interpolation"><span class="token punctuation">{</span> f <span class="token punctuation">.</span> __name__ <span class="token punctuation">}</span></span> <span class="token string">, args: </span><span class="token interpolation"><span class="token punctuation">{</span> args <span class="token punctuation">}</span></span> <span class="token string">, kwargs: </span><span class="token interpolation"><span class="token punctuation">{</span> kwargs <span class="token punctuation">}</span></span> <span class="token string">"</span></span> <span class="token punctuation">)</span> <span class="token keyword">return</span> f <span class="token punctuation">(</span> <span class="token operator">*</span> args <span class="token punctuation">,</span> <span class="token operator">**</span> kwargs <span class="token punctuation">)</span> <span class="token keyword">return</span> wrap <span class="token comment"># Applying decorator to a function</span> <span class="token decorator annotation punctuation">@trace</span> <span class="token keyword">def</span> <span class="token function">add_two</span> <span class="token punctuation">(</span> x <span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">return</span> x <span class="token operator">+</span> <span class="token number">2</span> <span class="token comment"># Calling the decorated function</span> add_two <span class="token punctuation">(</span> <span class="token number">3</span> <span class="token punctuation">)</span> <span class="token comment"># Applying decorator to a lambda</span> <span class="token keyword">print</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> trace <span class="token punctuation">(</span> <span class="token keyword">lambda</span> x <span class="token punctuation">:</span> x <span class="token operator">**</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">(</span> <span class="token number">3</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> |
add_two()
, has been decorated with @trace . And with lambda it is called through the guys like in the example above. and the result will be
1 2 3 4 | [TRACE] func: add_two, args: (3,), kwargs: {} [TRACE] func: <lambda>, args: (3,), kwargs: {} 9 |
Lambda Abuse
For a few examples in this article, that can be considered lambda abuse. If you find yourself trying to fix something the lambda doesn’t support, this could be a sign that a normal function would be more suitable. In this section we will look at a few examples so avoid using lambda.
Raise exception
Raising an exception using lambda is not a good idea.
1 2 3 4 5 6 7 8 | >>> def throw(ex): raise ex >>> (lambda: throw(Exception('Something bad happened')))() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <lambda> File "<stdin>", line 1, in throw Exception: Something bad happened |
This should be avoided. If you come across code like this, consider revising it.
Cryptic Style
As with any language, you can find it difficult to find the code you want if the style used makes it difficult to read. And the lambda is such a kind.
1 2 3 | >>> (lambda _: list(map(lambda _: _ // 2, _)))([1,2,3,4,5,6,7,8,9,10]) [0, 1, 1, 2, 2, 3, 3, 4, 4, 5] |
(_)
refers to a value without using it. But in this example, _
refers to different variables. And let’s name the variables for visibility.
1 2 3 4 | >>> (lambda some_list: list(map(lambda n: n // 2, some_list)))([1,2,3,4,5,6,7,8,9,10]) [0, 1, 1, 2, 2, 3, 3, 4, 4, 5] |
Admittedly, it’s still hard to read. Still utilizing the lambda, we’ll convert it as a regular function to make it easier to read.
1 2 3 4 5 6 | >>> def div_items(some_list): div_by_two = lambda n: n // 2 return map(div_by_two, some_list) >>> list(div_items([1,2,3,4,5,6,7,8,9,10]))) [0, 1, 1, 2, 2, 3, 3, 4, 4, 5] |
Class
You can, but shouldn’t, write class methods as Python lambda functions. The following example is perfectly valid. For example, instead of implementing str as a regular function, we use lambda. Similarly, brach
and year
are properties also implemented with lambda functions, instead of functions or decorators:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Car: """Car with methods as lambda functions.""" def __init__(self, brand, year): self.brand = brand self.year = year brand = property(lambda self: getattr(self, '_brand'), lambda self, value: setattr(self, '_brand', value)) year = property(lambda self: getattr(self, '_year'), lambda self, value: setattr(self, '_year', value)) __str__ = lambda self: f'{self.brand} {self.year}' # 1: error E731 honk = lambda self: print('Honk!') # 2: error E731 |
When running a tool like flake8
, a tool check style, it will be displayed
1 2 | E731 do not assign a lambda expression, use a def |
While flake8
doesn’t indicate an issue with using Python lambda functions in properties, they are difficult to read and error prone due to using multiple strings like brand
and year
. And always use this for deployment
1 2 3 4 5 6 7 8 9 10 11 | def __str__(self): return f'{self.brand} {self.year}' @property def brand(self): return self._brand @brand.setter def brand(self, value): self._brand = value |
As a general rule of thumb, prefer regular functions over lambda expressions.
When to use Lambda
Lambda is always the subject to fight against difficult to read and understand problems. But let’s ignore it and learn when to use lambda
Class constructor
Lambda is often used with map()
, filter()
. Here are a few examples of lambda use for those functions.
1 2 3 4 5 6 7 8 | >>> list(map(lambda x: x.upper(), ['cat', 'dog', 'cow'])) ['CAT', 'DOG', 'COW'] >>> list(filter(lambda x: 'o' in x, ['cat', 'dog', 'cow'])) ['dog', 'cow'] >>> from functools import reduce >>> reduce(lambda acc, x: f'{acc} | {x}', ['cat', 'dog', 'cow']) 'cat | dog | cow' |
You may have read code similar to the examples above, and it is quite common that it makes its use more efficient.
Key Functions
Key functions in Python are high-level functions that use a parameter key
as a named argument. Key
accepts a function that can be lambda. This function directly affects the algorithm controlled by the main function itself. Here are some of the main functions:
1 2 3 4 5 6 7 | >>> ids = ['id1', 'id2', 'id30', 'id3', 'id22', 'id100'] >>> print(sorted(ids)) # Lexicographic sort ['id1', 'id100', 'id2', 'id22', 'id3', 'id30'] >>> sorted_ids = sorted(ids, key=lambda x: int(x[2:])) # Integer sort >>> print(sorted_ids) ['id1', 'id2', 'id3', 'id22', 'id30', 'id100'] |
synthetic
After this article you learned:
- What is Lambda
- Origin, usage
- How to use or avoid
Hope this article has helped everyone in working with python.