What does a Python function's __name__ hold, and how does __qualname__ differ from it?
answer
- One is bare, one carries context
- Where the def physically sits
- A method shows its class
- Nested definitions get a marker segment
- Pickle needs the path, not the bare name
basics
~20 sname is the bare name from the def statement. qualname is the dotted path to the definition inside its module, including enclosing classes and functions, with <locals> marking a function-local definition. module names the defining module.
solid answer
~40 s`__name__` is the plain identifier the `def` used: `'render'`. `__qualname__` is the **qualified** path from module level down to the definition, so a method defined in `class Report` has `__qualname__ == 'Report.render'` while its `__name__` is still `'render'`, and a function defined inside another function gets `'outer.<locals>.inner'`. `__module__` holds the name of the module the function was defined in, matching a key in `sys.modules`. Together they identify a function uniquely enough that `pickle` uses `__module__` plus `__qualname__` to serialize a module-level function by reference. All three are plain writable attributes on the function object, which is why decorators can copy them, and why log formatting or a registry should prefer `__qualname__` when two classes both define `render`.
code
pycon · 15 lines>>> class Report:
... def render(self):
... pass
...
>>> Report.render.__name__, Report.render.__qualname__
('render', 'Report.render')
>>> def outer():
... def inner():
... pass
... return inner
...
>>> outer().__qualname__
'outer.<locals>.inner'
>>> (lambda x: x).__name__
'<lambda>'go deeper
Recall that name is the bare def name and qualname adds the enclosing class or function, and that lambdas report '<lambda>'. Being able to read these off a function is enough here.
Explain why the qualified form was needed, what <locals> marks, and how module plus qualname combine into a stable identifier that decorators must preserve.
Show where the choice matters in a running system: metric and log labels that collapse when keyed on the bare name, registry keys, and pickling by reference across process boundaries.
Set the convention for how code paths are identified across services and dashboards, and make preserving these attributes a requirement for any shared decorator, since observability and serialization both depend on them.
### Three attributes that name a function Every Python function object carries three naming attributes, set when the `def` statement executes: - **`__name__`** — the identifier that followed `def`. For a lambda it is `'<lambda>'`. It is a bare name with no context whatsoever. - **`__qualname__`** — the *qualified* name: the path from module top level to this definition, joined with dots. Enclosing classes contribute their names; an enclosing function contributes its name plus the literal segment `<locals>`. - **`__module__`** — a string naming the module in which the function was defined, the same string used as its key in `sys.modules`. For a script run directly it is `'__main__'`. So for a method `render` defined in `class Report` in module `reports.nightly`: `__name__` is `'render'`, `__qualname__` is `'Report.render'`, `__module__` is `'reports.nightly'`. ### Why the qualified form exists `__name__` alone is ambiguous almost immediately. A codebase with `CsvReport.render`, `HtmlReport.render` and a module-level helper `render` has three objects whose `__name__` is `'render'`. Anything that keys on the bare name — a log field, a metrics label, a dispatch table, a cache of function results across a codebase — collides. `__qualname__` was introduced to give the bare name its context, and it is why a function's `repr()` shows the qualified form: `<function Report.render at 0x...>`. The `<locals>` segment is the part people trip over. It appears whenever a definition happened inside a function body, because such a definition is not reachable by attribute lookup from the module: you cannot write `outer.inner` and get it. The segment is a deliberate marker that the path is *descriptive*, not *navigable*. That is exactly the case for a decorator's inner wrapper, whose qualname reads `deco.<locals>.wrapper` — seeing that string in a log or a traceback is the standard tell that a decorator did not preserve metadata. ### Where they are actually consumed Three consumers matter in practice. **Serialization.** `pickle` does not serialize a function's code; for a module-level function it stores a reference built from `__module__` and `__qualname__`, and unpickling imports that module and walks that path. If either attribute lies — because a decorator rebound the name to a wrapper, or because the function was defined inside another function — pickling by reference fails. This is the concrete reason a function that has to cross a process boundary must be defined at module level and must not have its naming attributes clobbered. **Observability.** Log records, span names and metric labels that identify the code path read these attributes. A nightly report generator that labels every timing metric with `func.__name__` produces one merged series for every renderer named `render`; switching the label to `__qualname__` separates them without any other change. **Registries and error messages.** A decorator that registers renderers wants a stable key; `f"{fn.__module__}.{fn.__qualname__}"` is the conventional one, unique within a process and readable in a failure report. Frameworks that raise on duplicate registration use exactly this string. ### They are writable, and that is the point None of these attributes is computed on demand — they are stored values, and on a plain Python function they can be reassigned. That is what lets `functools.wraps` copy `__module__`, `__name__` and `__qualname__` from a wrapped function onto a wrapper so the decorated object keeps identifying itself correctly. It also means they can be made to lie, deliberately or accidentally, so treat them as helpful labels rather than as proof of what an object really is. One related distinction worth keeping straight: the function object's `__name__` is not the same thing as the module-level `__name__` global that the `if __name__ == "__main__":` idiom tests. That one is a module attribute holding the module's own name; the function's is an attribute of the function object. Both are spelled `__name__`, and the confusion is common enough to be worth stating out loud. ### A caution about trusting them Because these are stored, writable strings rather than derived facts, they can disagree with reality. A wrapper that copied a wrapped function's names identifies itself as that function even though it runs different code; dynamically created functions can be given any qualname the creator likes. Treat them as labels intended for humans and for tooling that consents to be told, not as an identity check. When you need to know whether two names refer to the same object, compare the objects with `is`; when you need to know where the code actually lives, read the code object's file and line rather than the qualified name. ### The interview shape Define both, give a class-method example where they differ, mention `<locals>` and what it signals, and name one real consumer — pickling, logging labels, or registry keys.
- What does the <locals> segment in a __qualname__ tell you?That the function was defined inside another function's body, so the path is descriptive rather than navigable — you cannot reach the object by attribute lookup from the module. Seeing `deco.<locals>.wrapper` in a log line or traceback is the usual sign that a decorator returned a wrapper without copying the wrapped function's metadata.
- Why does pickling a function care about these attributes?`pickle` serializes a module-level function by reference, storing `__module__` and `__qualname__` and re-importing that path on load. If a decorator rebound the name to a wrapper whose qualname is `deco.<locals>.wrapper`, or the function is defined inside another function, the path does not resolve and pickling fails.
- Is a function's __name__ related to the module-level __name__ used in the main-guard idiom?No. They only share a spelling. The function attribute is stored on the function object and holds the identifier from its `def`; the global tested by `if __name__ == "__main__":` is the enclosing module's own name attribute, set to `'__main__'` when that module is the entry point.
name is a first name and qualname is the full name plus department: fine in a two-person team, essential once three departments each employ a Render.
saying these in an interview costs you the question
- Thinks __qualname__ is just the fully dotted import path with the module
- Believes these attributes are read-only
- Cannot explain the <locals> segment
- Confuses the function __name__ with the module-level __name__ global
- Assumes __module__ holds a filesystem path