Python Names, Scopes, and Namespaces
Understand how Python binds names, organizes namespaces, resolves names through nested scopes, and uses global and nonlocal when rebinding is intentional.
Basic
A name is a label that refers to an object. A namespace is a place where those name-to-object bindings are kept. A scope is the part of a program where a namespace can be accessed directly by an unqualified name.
Names and namespaces
Python does not make a name itself contain a value. Instead, a name is bound to an object. Different namespaces can contain the same name without interfering with one another.
score = 10
def show_score():
score = 20
print(score)
show_score()
print(score)The function call has a local name named score; the module-level score remains 10.
The module-level name and the function-local name are different bindings even though both are spelled
score.
Local and global scopes
A function call creates a local namespace for that invocation. Names bound inside the function are normally local. Names defined at module level belong to the module global namespace.
message = "module"
def read_message():
print(message)
read_message()A function can read a name from an enclosing scope when it has not created a local binding with that name.
A name used inside a function is not automatically local just because the function uses it. What matters is whether the function block binds that name.
How Python resolves a name
For an ordinary function, Python searches the current local scope first, then enclosing function scopes, then the module global scope, and finally the built-in namespace.
language = "Python"
def outer():
topic = "scopes"
def inner():
print(topic)
print(language)
print(len("ok"))
inner()
outer()The inner function finds topic in the enclosing function, language in the module, and len in the built-in namespace.
If no binding can be found, Python raises
NameError.
An assignment can make a name local
If a function contains a binding operation for a name, that name is treated as local to that function unless the function explicitly declares it
global or
nonlocal.
count = 10
def read_before_local_assignment():
print(count)
count = count + 1
def read_missing_name():
print(missing_name)
for function in (read_before_local_assignment, read_missing_name):
try:
function()
except NameError as error:
print(type(error).__name__)The function that assigns to count treats it as local throughout the function, so its earlier read raises UnboundLocalError. The second function has no binding for missing_name in its available namespaces, so it raises NameError.
A binding operation anywhere in a function block makes that name local throughout the block unless
global or
nonlocal changes the rule. Python does not fall back to a module-level name when the local binding has not received a value. The resulting
UnboundLocalError is a subclass of
NameError; a plain
NameError means name resolution found no binding for the requested name in the namespaces that apply.
This rule is why a seemingly harmless assignment can change how Python interprets another use of the same name inside the function.
Rebinding a module-level name with global
Use
global when a function needs to rebind a name in its module global namespace. It is usually clearer to pass values in and return new values when that design works.
count = 0
def increase():
global count
count += 1
increase()
increase()
print(count)global tells the function that assignments to count should update the module-level binding.
Rebinding an enclosing function name with nonlocal
Use
nonlocal when a nested function needs to rebind a name that already exists in the nearest enclosing function scope.
def make_counter():
count = 0
def next_count():
nonlocal count
count += 1
return count
return next_count
counter = make_counter()
print(counter())
print(counter())nonlocal lets next_count() update the count binding belonging to make_counter().
The name must already exist in an enclosing function scope; otherwise
nonlocal causes a
SyntaxError.
Prefer the smallest useful scope
Local names are often easier to reason about because their lifetime and effect are limited. Prefer parameters and return values for ordinary data flow; use
global or
nonlocal deliberately when shared state is genuinely part of the design.
Key idea: names, namespaces, and scopes explain why the same spelling can refer to different objects in different parts of a program.
Thanks for your feedback.
Mark this learning resource complete to track your learning progress.