01 / 04

What is a lambda function, and what are its limitations compared to a regular function?

Difficulty: 3/10
Functional Programming Tools, Lambda Functions, Anonymous Functions and Closures

Lambda expressions and their limits

A lambda is an anonymous function created with an expression: lambda params: expression. It produces an ordinary function object (type function, name '<lambda>') whose body is a single expression that is evaluated and returned implicitly. It supports the full parameter syntax (defaults, *args, keyword-only, **kwargs) and closes over variables like any nested function; the difference from def is purely syntactic. It exists so that a small function can be written inline where one is needed, such as a sort key or a callback.

javascript

Limitations compared with def: the body must be one expression, so no statements (assignment, return, raise, try, with, for, while, import, del, assert), though you can use conditional expressions, comprehensions, function calls and a parenthesized walrus. A lambda has no docstring and cannot carry parameter or return annotations, so type checkers must infer its type from context. Its name in tracebacks and profilers is <lambda>, which makes debugging harder than with named functions. It cannot be pickled by name (so it fails with multiprocessing and some serialization), and because it is anonymous it is harder to test and reuse. Python 3 also removed tuple parameter unpacking (PEP 3113), so lambda (a, b): ... from Python 2 is invalid.

How I use them: lambdas are good for short, throwaway callables: sort and min/max keys, a simple callback, a default_factory, or a dispatch-table entry. If the logic needs a name, a comment, multiple steps, or reuse, I use def. PEP 8 discourages assigning a lambda to a name (lint rule E731), since def gives a proper name and traceback and has no downsides. Often a standard-library helper is clearer than a lambda: operator.itemgetter and attrgetter for keys, functools.partial for pre-filling arguments, str methods or builtins like len passed directly.

Common mistakes: closures in loops that capture the variable instead of its value (the [2, 2, 2] example; fix with a default argument or functools.partial), writing lambdas so dense that a nested conditional expression is unreadable, and expecting lambdas to work with multiprocessing or pickle. There is no version-specific change to lambda semantics in recent Python 3 releases.

Scenario Questions

0-2 years experience

  1. 1Write a lambda that returns the larger of two numbers and call it. Why might you use def instead in real code?
  2. 2Sort a list of words by length using a lambda as the key.

2-5 years experience

  1. 1Why does lambda x: return x fail? List what can't appear in a lambda body and how you would work around those limits.
  2. 2A traceback shows <lambda>. How does that affect debugging, and what does PEP 8 recommend about assigning lambdas to names?

5-8 years experience

  1. 1Buttons created in a loop each have a lambda callback and all print the last index. Explain why and fix it.
  2. 2Choose between lambda, operator.itemgetter or attrgetter, functools.partial and def for (a) sorting records, (b) pre-filling arguments and (c) multi-step logic. Justify each choice.

8+ years experience

  1. 1Can lambdas be pickled or used with multiprocessing? How does that affect the design of an API that accepts callbacks?
  2. 2How do you annotate a parameter that accepts lambdas (Callable, Protocol), why can't a lambda itself carry annotations, and how do type checkers infer its type?

Follow-up Questions

  • Why does PEP 8 discourage assigning a lambda to a variable name?
  • Why do lambdas created in a loop all return the same value, and how do you fix it?
Share

Share via WhatsApp, X, Facebook, LinkedIn or copy link. Open Graph preview enabled.