Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

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 globals, and built-ins—the order commonly remembered as LEGB.

What scope means in Python

A scope is a textual region where a namespace can be accessed directly. A namespace maps names to objects. Python’s tutorial on scopes and namespaces describes how names are found and how scopes relate to one another.

For an ordinary function, LEGB describes the lookup sequence:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. Local: names bound in the current function.
  2. Enclosing: names in enclosing function scopes, checked from the nearest outward.
  3. Global: names in the module where the code was defined.
  4. Built-in: names provided by Python’s built-ins.

Python uses this order when resolving an unqualified name. LEGB is a useful model, but not every syntactic block creates an ordinary scope; class bodies and certain special execution contexts follow additional rules.

How assignment determines local names

Inside a function, assigning to a name makes it local by default. Python determines that from the function’s code, not from the order in which the statements happen to run. The binding is local throughout the function unless a declaration says otherwise.

This is why a read before assignment can raise UnboundLocalError, rather than falling back to a global with the same name:

count = 10

def increment():
    count += 1  # UnboundLocalError: count is treated as local

The augmented assignment needs the current value of count before it can store the incremented value. Since the function’s assignment makes count local, that local has no value yet when it is read. The Python execution model describes how name bindings determine local scope.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

When to use plain assignment, nonlocal, or global

These forms differ in which namespace receives a binding and whether that binding must already exist.

Form Where the binding goes Must it already exist? Visible after the function returns?
Plain assignment The current function’s local scope No No; the local binding ends with that call
nonlocal name The nearest enclosing function scope that binds the name Yes; otherwise Python raises SyntaxError Yes, to code using that enclosing binding
global name The current module’s global namespace No; the module binding can be created if absent Yes, to code using that module binding

“Global” means the module’s namespace, not one universal variable shared across every module. Python’s language reference for simple statements explains the nonlocal declaration; the programming FAQ also covers local and global variable rules.

Plain assignment creates a local binding

A nested function that assigns to a name without a declaration creates its own local binding. It does not change a same-named variable in an enclosing function.

Use nonlocal to rebind an enclosing function’s name

nonlocal directs reads and assignments to a name already bound in the nearest enclosing function scope. It cannot create that enclosing binding: if no suitable enclosing function binding exists, the code is invalid and raises SyntaxError.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use global to rebind a module-level name

global makes references and assignments to the declared name in the current code block refer to the module’s global namespace. For example:

count = 10

def increment():
    global count
    count += 1

Here, the assignment updates the module’s count instead of creating a local one.

What nested assignments actually change

This example shows the difference between a local assignment, a nonlocal rebind, and a module-level name:

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() assigns its own local message, leaving outer’s binding unchanged. change_outer() rebinds the nearest enclosing function’s message. Neither operation changes the module-level message.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Why class scope is a special case

A class body executes with its own namespace, so names assigned in the body become class attributes. But that namespace does not become a lexical enclosing scope for methods. An unqualified name in a method is resolved through the method’s local and enclosing function scopes, the defining module’s globals, and built-ins—not by searching the class namespace. Access class or instance attributes through the class or an instance, such as MyClass.setting or self.setting.

This is one reason LEGB should be treated as a model for ordinary name lookup, not a claim that every block adds a scope. Python’s execution model documentation also addresses special handling for annotation scopes and code executed with exec() or eval().

Choosing a clear approach to shared state

global and nonlocal are language features, but explicit state is often easier to follow in application code. Consider returning an updated value, passing state as an argument, or encapsulating mutable state in an object when that makes dependencies clearer. Use a declaration when rebinding an enclosing or module-level name is genuinely the intended behavior.

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.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.