Like many a new, or seasoned Python developer I often find myself scratching my head at lambda functions whenever I encounter one, simply because of never taking the short amount of time to understand them.

After finally getting fed up with them being nothing more than a source of confusion and taking the time to learn about how they work, it turns out lambda functions are not that confusing after all.


So...What is a lambda function?

In Python (and many other languages) a lambda function is simply an anonymous function, containing only a single expression.

A simple example is a lambda function used to raise x to the power of 2.

lambda x: x ** 2

Here we have the lambda keyword to denote that this is a lambda function, followed by the lambda's argument x. The lambdas single expression is then on the right-hand side of the colon. The result of the expression will end up being the return value of the lambda function.

A more practical example is passing a lambda function as the filtering function passed into the built-in filter() function.

# Create a list of all even numbers between 0-10.
filtered = [n for n in filter(lambda x: x % 2 == 0, range(0,11))]
print(filtered)

>>> [0, 2, 4, 6, 8, 10]

In this example the lambda function is invoked by the filter function it is passed to. Each element in the iterable range(0,11) is then passed into the lambda's argument x, the lambdas expression evaluates if the number is odd or even and returns true or false accordingly. Only values that evaluated to true in the lambda function are then included in the resulting iterable created by the filter() function.

The same outcome can also be achieved with a regular Python function. This approach, despite being more verbose may be preferable as it is clearer exactly what the filter functions intended behaviour is, and if there is a requirement to write a unit test for the filter function.

def filter_even(x):
    return x % 2 == 0

# Create a list of all even numbers between 0-10.
filtered = [n for n in filter(filter_even, range(0,11))]
print(filtered)

Performance?

Given the vastly different syntax compared to a normal function definition, one would be forgiven for thinking that the Python runtime executes lambda functions differently, resulting in either some change in performance.

This is not the case, as can be seen in the below disassembled Python bytecode, the only difference is that the standard Python function has a name where the lambda function is simply named lambda.

print(dis("def filter_even(x): return x % 2 == 0"))

# Standard Python function bytecode
Disassembly of <code object filter_even at 0x101b0bea0, file "<dis>", line 1>:
  1           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MODULO
              6 LOAD_CONST               2 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE
            
print(dis("lambda x: x % 2 == 0"))

# Lambda function bytecode
Disassembly of <code object <lambda> at 0x10b59cd40, file "<dis>", line 1>:
  1           0 LOAD_FAST                0 (x)
              2 LOAD_CONST               1 (2)
              4 BINARY_MODULO
              6 LOAD_CONST               2 (0)
              8 COMPARE_OP               2 (==)
             10 RETURN_VALUE

Conclusion

The main benefit of lambda functions is the ability to define a single-use, single responsibility function that can be easily passed around.

There are however several drawbacks associated with them.

  • Unfamiliar syntax.
  • Not testable.
  • Not possible to provide a docstring.
  • Difficult to comprehend tracebacks due to lambda functions having no defined name.

Because the drawbacks largely outweigh the benefits, I would likely stay away from lambda functions for anything aside from simple functions provided as arguments to functions such as sorted(), map() and filter().