Why does a traceback frame read '<lambda>', and what does PEP 8 advise about it?
answer
- The function has no name to record
- Diagnostics read __name__
- PEP 8 targets the assignment, not lambdas
- One line of def buys back the name
- Also docstrings, annotations, pickling
basics
~20 sEvery lambda records the literal name '<lambda>', so tracebacks, logs and profiles cannot tell one from another. PEP 8 says that binding a lambda to a name with = should be a def instead, which restores the real name.
solid answer
~50 sA lambda has no name of its own: its `__name__` and the tail of its `__qualname__` are the literal string `'<lambda>'`. Tracebacks, `repr` output, logging and profiler reports all read those attributes, so twenty lambdas assigned to twenty names all report identically and an error tells you only the file and line. PEP 8 addresses exactly this: if you are binding a lambda to an identifier with `=`, write `def` instead — the assignment already gave up anonymity, which was the lambda's only advantage, and the `def` costs one line while restoring the name in every traceback, log record and profile, plus a docstring and annotations. It also makes the function picklable, which matters as soon as a callable has to cross to a worker process. Inline lambdas passed straight into a call are untouched by the rule.
code
python · 8 linessubject_of = lambda user: user["name"].title()
def body_of(user):
return user["name"].lower()
print(subject_of.__name__, "|", subject_of.__qualname__)
print(body_of.__name__, "|", body_of.__qualname__)
print(repr(subject_of))go deeper
Recall the rule in one line: if you are about to write name = lambda ..., write def name(...) instead. Knowing that a traceback will otherwise say <lambda> is enough at this level.
Explain the mechanism rather than citing the style guide: the code object stores the literal '<lambda>', and tracebacks, repr, logging and profilers all read it. Add the secondary losses — no docstring, no annotations, awkward breakpoints.
Demonstrate having debugged this. Talk through what an alert containing only <lambda> and a line number costs at 3am, why pickling failures surface later when the callable must reach a worker process, and how you convert incrementally rather than in one risky sweep.
Own the policy and its boundary: the ban is on assigned lambdas, not on inline ones, and it is enforced by tooling rather than by review argument. Frame it as observability — every frame in production should carry a name someone can grep for.
## What the frame name comes from When CPython compiles a function it stores a name in the code object. A `def` stores the identifier you wrote. A lambda has no identifier to store, so the compiler stores the literal string `'<lambda>'`, and that string becomes the function's `__name__` and the last segment of its `__qualname__`. Every downstream consumer of a function's identity reads those attributes: the traceback formatter, `repr()` of the function, the function-name field of a standard logging record, profiler tables, and most monitoring agents that aggregate by frame. So a stack line such as `File "digest.py", line 41, in <lambda>` is not a bug and not a special error state — it is the only name that exists. The consequence is operational. Imagine a nightly email-digest sender that builds its per-recipient formatting rules as a dozen lambdas bound to a dozen names. When one of them raises on a malformed record, the on-call engineer's alert says `<lambda>` and a line number. If the file has been edited since the release that is running, even the line number lies. Every one of those frames would have carried a real, greppable name had the author typed `def`. ```python format_subject = lambda user: user["name"].title() def format_subject_def(user): return user["name"].title() print(format_subject.__name__) # <lambda> print(format_subject_def.__name__) # format_subject_def ``` ## What PEP 8 actually says The style guide's rule is narrow and worth quoting accurately: always use a `def` statement instead of an assignment statement that binds a lambda expression directly to an identifier. Its stated reason is that the `def` form is more useful for tracebacks and string representations, and that the assignment removes the sole benefit a lambda offers over a `def` — that it can be embedded inside a larger expression. Note the boundary. The rule is about `name = lambda ...`, not about lambdas in general. A lambda passed inline as a sorting key, a callback or a factory argument is exactly what the form is for, and PEP 8 has no objection to it. Linters ship a check for the assigned-lambda pattern, and it is one of the few style checks that is nearly always right, because the fix is mechanical and lossless. ## What else the assignment costs **Debugging.** Setting a breakpoint inside a one-line body is awkward, and stepping through it gives you no name to anchor on. A `def` body is a normal block with normal line boundaries. **Documentation and typing.** A lambda cannot hold a docstring and its parameters cannot be annotated, so a named lambda is invisible to a type checker's parameter-level checking and to any tooling that harvests docstrings. A `def` gets both for free. **Serialization.** The standard pickling protocol serialises a function by reference — module plus qualified name — and then verifies that looking that name up again yields the same object. `'<lambda>'` is not a resolvable name, so pickling a lambda fails. That turns into a real production failure the first time someone hands the callable to a worker process that requires a picklable payload, or tries to cache it. A `def` at module level pickles by reference without any of this. **Decoration.** Decorator syntax applies to a `def` or a `class`; decorating a named lambda means calling the decorator by hand around the assignment, which reads worse than the `def` would have. **Grep.** `def format_subject` is findable. `format_subject = lambda` is findable too, but the traceback that sent you looking said `<lambda>`, so you had nothing to grep for in the first place. ## Diagnosing it after the fact If you inherit a codebase full of named lambdas and a stack of `<lambda>` frames, the file and line in the traceback still locate the code; use them, then convert as you go rather than in one sweeping change. If you need to distinguish frames at runtime before converting, `__qualname__` at least tells you which enclosing function the lambda was defined in, which narrows a large module considerably. Some codebases reassign `__name__` on the function object after creating it — that fixes logging output but not the traceback, which reads the *code object's* name, so it is a half-measure that misleads the next reader. Convert to `def`. ## The judgement being tested This is a production-experience question. The junior answer is "PEP 8 says don't". The answer that lands names the mechanism (`__name__` is the literal `'<lambda>'` and every diagnostic reads it), names the concrete costs (tracebacks, logs, profiles, pickling, annotations, breakpoints), and draws the boundary correctly: the rule is about the *assignment*, and inline lambdas remain entirely idiomatic.
- Does PEP 8 discourage lambdas passed inline as arguments?No. The rule is specific to binding a lambda to an identifier with `=`. A lambda handed straight to a call — an ordering key, a callback, a factory argument — is the form's intended use and stays idiomatic. Reading the rule as a general ban on lambdas is a common overcorrection that makes code longer without making it clearer.
- Can you fix the traceback by setting __name__ on the lambda after creating it?Not really. Assigning `__name__` changes what `repr` and a logging record's function-name field report, but the traceback formatter reads the name stored in the *code object*, which still says `<lambda>`. So you get a partial fix that makes logs and stacks disagree — worse for the next reader than either state alone. Convert to a `def`.
- Why does pickling a lambda fail while pickling a module-level def succeeds?The standard protocol serialises a function by reference: it records the module and qualified name, then checks that resolving that name yields the same object. `'<lambda>'` is not a resolvable attribute, so the check fails. A module-level `def` has a real qualified name that resolves, so only the reference travels — which is also why the receiving side must be able to import the same module.
saying these in an interview costs you the question
- Reads PEP 8 as banning lambdas everywhere
- Thinks '<lambda>' in a traceback indicates a bug
- Believes assigning __name__ fixes the traceback
- Says a named lambda can carry a docstring
- Assumes any callable can be pickled and sent to a worker process
- Argues the rule is cosmetic with no operational cost