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.
References: Python scopes and namespaces, Naming and binding. See it in use in Python Functions, Modules, and Classes.
Discover more from Insightful Data Lab
Subscribe to get the latest posts sent to your email.
