Variable Scope
Scope is the region of code where a name can be found. Python looks for a name in the local function first, then in any enclosing function, then at module level, and finally among the built-ins. Each call has its own local bindings. This does not make the referenced objects private: two calls can receive the same mutable object, and an inner function can retain an enclosing binding after the outer function returns.
Reading a module-level name from inside a function works. Without a global or nonlocal declaration, assigning to a name in the body makes that name local for the entire body, including lines before the assignment. Reading it first then raises UnboundLocalError: cannot access local variable 'counter' where it is not associated with a value, which is the usual explanation for a function that seems to have lost a value defined above it.
global name and nonlocal name declare that assignment should reach an outer scope. global targets the module namespace; nonlocal requires an existing binding in an enclosing function. Both can intentionally manage shared state. Tests must control that state as well as the arguments. For this counter example, passing a value in and returning the new one makes the dependency easier to see.
Two related effects are worth knowing. A local name can shadow an outer one, so a parameter called list or sum hides the built-in for the rest of that function. And a notebook keeps module-level names in the kernel between cells, so a function that reads such a name can appear to work until the cells are run in a different order.
Further reading
See the worked examples in Python Functions, Modules, and Classes.
Discover more from Insightful Data Lab
Subscribe to get the latest posts sent to your email.
