nonlocal vs global: rebinding names in outer scopes
Both keywords let a function rebind a name that lives in an outer scope instead of creating a new local. global targets the module-level namespace. nonlocal targets the nearest enclosing function scope that already has that name, and it is a SyntaxError if there is none; it can never reach module level. nonlocal exists to make closures with mutable state possible: without it, assignment inside the inner function creates a new local variable.
The crucial distinction interviewers look for is rebinding versus mutating. You only need these keywords when you assign to the name (x = ..., x += 1). Calling items.append(x) or d[k] = v mutates the object the name points to and works with plain lookup through LEGB. Mechanically, a variable referenced by a nested function is stored in a cell object shared between the outer and inner frames (visible via closure and LOAD_DEREF), and nonlocal makes assignments write into that cell.
Trade-offs and alternatives: nonlocal closures are compact for small callbacks and counters, but state hidden in a closure is hard to inspect, test and reset. For anything non-trivial I prefer a small class with attributes, itertools.count for sequences, or a generator that yields successive values. global should be rare: it creates hidden coupling and complicates tests and concurrency, so prefer passing arguments or using a config object. Closures also keep every referenced outer variable alive, which can retain large objects.
Common mistakes: using global when the variable is in an enclosing function (it will refer to the module-level one, or create a new global), expecting a nonlocal counter shared across threads to be safe (the read-modify-write is not atomic; use a lock or atomic structure, which also matters with free-threaded builds), and forgetting the late-binding behavior of closures defined in loops. nonlocal has existed since Python 3.0 (PEP 3104); Python 2 had no equivalent, so old code used a one-element list workaround.
0-2 years experience
2-5 years experience
5-8 years experience
8+ years experience