Python treats a name assigned anywhere in a function as local throughout that function unless you declare it global or nonlocal. When Python looks up an unqualified name, it checks the local scope, enclosing function scopes, the module’s global namespace, and then built-ins—the order summarized by LEGB. Knowing the difference between looking up a name and binding one explains common errors such as UnboundLocalError.
What scope means in Python
A scope is a part of a program where a namespace can be accessed directly. A namespace maps names to objects; scopes determine which namespace Python consults for a name. The Python Tutorial describes a scope as “a textual region of a Python program where a namespace is directly accessible.” Python Tutorial: Scopes and Namespaces
As an Amazon Associate I earn from qualifying purchases.
A name is not the object itself. Assigning a name creates or changes a binding in a namespace. The same spelling can refer to different objects in different namespaces: a function-local message does not automatically replace a module-level message.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
How LEGB name lookup works
For an ordinary unqualified name inside a function, Python searches these scopes in order:
#1 Best Overall
- Local: the current function’s local namespace.
- Enclosing: enclosing function scopes, from the nearest outward.
- Global: the namespace of the module where the code is defined.
- Built-in: Python’s built-in names, such as
len.
This lookup order is commonly called LEGB. If a name is not found in any applicable scope, Python raises NameError. LEGB is a useful model for normal function code, but it does not mean every block of code creates another ordinary lexical scope.
How assignment changes the rule
Lookup and binding are related but distinct. Python determines a function’s local names by examining assignments in that function’s code. If the function assigns to a name anywhere in its body, Python treats that name as local throughout the function unless a global or nonlocal declaration says otherwise.
Rank #2
Why a read before assignment raises UnboundLocalError
A function does not fall back to a same-named global simply because its local variable has not received a value yet. For example:
count = 10
def increment():
count += 1
increment()
The augmented assignment needs to read count before it can add one. Because the function assigns to count, Python classifies it as local, and that local has no value at the read. Calling increment() therefore raises UnboundLocalError, a subclass of NameError.
Local, nonlocal, and global assignment compared
| Code in a function | Where the binding changes | What must already exist? | Visible after the function returns? |
|---|---|---|---|
| Plain assignment | The current function’s local namespace | No | No change to an enclosing or module binding |
nonlocal name |
The nearest enclosing function scope that binds name |
Yes; otherwise the code raises SyntaxError |
Yes, to code that uses that enclosing binding |
global name |
The current module’s global namespace | No; assignment can create the module binding | Yes, to code using that module’s binding |
Here, “global” means the module where the function is defined—not one universal variable shared across all modules. The language reference describes how Python determines local, global, and free-variable bindings in its execution model.
Use nonlocal to rebind an enclosing function variable
nonlocal applies to a name already bound in an enclosing function scope. Python changes the nearest such binding; it does not create a new name in the enclosing function. If there is no suitable enclosing binding, the declaration is invalid and raises SyntaxError. See the language reference for the nonlocal statement.
message = "module"
def outer():
message = "outer"
def local_only():
message = "inner local"
def change_outer():
nonlocal message
message = "changed outer"
local_only()
print(message) # outer
change_outer()
print(message) # changed outer
outer()
print(message) # module
local_only creates its own local message, leaving outer’s binding alone. change_outer uses nonlocal, so its assignment changes the binding in outer. The module-level value remains unchanged.
Recommended Free Tools
Use global to rebind a module-level name
A global declaration makes references and assignments to that name in the current function refer to the defining module’s global namespace. Applied to the earlier example, it makes the increment explicit:
Best Value
count = 10
def increment():
global count
count += 1
After increment(), the module’s count binding is 11. Use global when changing module state is intentional. In application code, returning a new value, passing state explicitly, or encapsulating it can make dependencies easier to see; Python does not prohibit globals.
The Python Programming FAQ also explains the rules for local and global variables, including why an assignment can make a name local throughout a function.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Why class scope is an exception to simple LEGB explanations
A class body has a namespace used while Python executes the class definition. But that namespace does not become an enclosing lexical scope for methods. A method does not resolve an unqualified name by searching the class body; class and instance data are normally accessed as attributes, such as self.name or MyClass.name.
For that reason, a method’s unqualified names follow the applicable local, enclosing-function, module-global, and built-in lookup rules—not a class-attribute lookup step. The execution model also includes special handling for contexts such as annotation scopes and code executed with exec() or eval(); LEGB is not a complete description of every such context.
Quick Recap
A practical way to diagnose a scope problem
- Find every assignment to the name in the function, including augmented assignments such as
+=. - If there is an assignment and no declaration, treat the name as local throughout that function.
- If the intended target is an enclosing function binding, use
nonlocaland confirm that the binding exists. - If the intended target is the defining module’s binding, use
global. - If the function only needs to read an enclosing or global name, it generally needs no declaration.
- For class data in a method, access it as an attribute rather than expecting the method to find the class-body name through LEGB.
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




