LEGB: Local, Enclosing, Global, Built-in
When Python looks up a bare name it searches four scopes in order: Local (the current function), Enclosing (any outer function scopes, innermost first), Global (the module's namespace), and Built-in (the builtins module, which supplies len, print, list and so on). The first match wins and the search stops. Only functions, modules, classes (with special rules), lambdas and, until 3.12, comprehensions create scopes; if, for, while, try and with blocks do not.
The key insight, and what separates a good answer: scope is decided at compile time, per function, by looking at where a name is assigned. If a function assigns to a name anywhere (including +=, for targets, import, and def), that name is local throughout the function. That is why reading it before assignment raises UnboundLocalError rather than falling back to the global value. To rebind a global or an enclosing variable you declare global or nonlocal; to merely read or mutate an object you do not need either.
Details worth knowing: names are resolved at call time, which gives rise to the late-binding closure behavior in the example; class bodies have their own namespace that nested functions and methods do not see as an enclosing scope (so a method must use self.attr or ClassName.attr); and an exception variable in except E as e is deleted at the end of the except block. Comprehensions had their own function-like scope in Python 3, and in 3.12 PEP 709 inlined them for speed while preserving the isolation semantics, so the observable behavior is the same.
Common mistakes: shadowing built-ins (list, dict, id, type, input) and later wondering why they stopped working; relying on module-level mutable globals, which complicates testing and concurrency (prefer passing parameters, dependency injection or contextvars); and assuming loops introduce a scope, so the loop variable leaks. At the bytecode level the rules appear as LOAD_FAST, LOAD_DEREF, LOAD_GLOBAL and LOAD_NAME.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience