Python Programming · Foundations

Scope

Want it in plain words first? Jump to Eli explains — the same idea, no jargon.
On this page 9 sections
  1. In 30 seconds
  2. Why this matters
  3. The college version
  4. Eli explains
  5. Worked example
  6. Key takeaway
  7. Quick check
  8. Study tools
  9. Sources & references

In 30 seconds

is the part of a Python program where a name can be found directly. When code uses an unqualified name, Python checks the current function's local names first, then names in enclosing functions, then the module's global names, and finally built-in names. This familiar sequence is often called LEGB. Assignment changes the picture: an assignment in a function normally creates or rebinds a local name unless global or nonlocal says otherwise.

Why this matters

Scope lets a reader predict which value a name means without guessing. It explains why a helper can read a module-level setting, why a nested function can remember surrounding state, and why a seemingly harmless count = count + 1 can fail. In coursework, scope is essential for tracing code and diagnosing name errors. In larger programs, deliberately choosing local, enclosing, or module-level state helps limit unintended interactions and makes changes safer to reason about.

The college version

Scope is about name visibility

A Python name is a label that code uses to reach a value. Scope answers a narrower question than what value this is: where may the program look for that label without qualifying it? For an ordinary name used inside a function, the search begins in the created for that call. If the name is absent there, Python can search the scopes of enclosing functions, beginning with the nearest. Next comes the of the module that defined the function. Finally, Python can use the , where names such as len live. LEGB is a convenient mnemonic for this local–enclosing–global–built-in order. The order matters only until a matching is found. If an inner function has a local label, that binding hides an enclosing or global label of the same spelling for uses inside the inner function. Outside that function, the local binding is not directly available. A scope rule is therefore a predictable lookup rule, not a claim that only one name with a particular spelling may exist in a program.

Reading differs from rebinding

Code inside a function may read an outer name when it does not bind that name locally. Assignment is the crucial event. If Python finds a name-binding operation anywhere in a function block, uses of that name in that block are treated as local by default. This is a whole-block rule, not a line-by-line discovery rule. That rule explains a common surprise. Suppose module code binds count = 10, then a function contains count = count + 1. The assignment means count is local in that function, so the expression on the right tries to read that local count before it has a value. Python raises UnboundLocalError; it does not fall back to the module value. The language reference identifies this as a special case of NameError. The repair is not to rely on a mysterious exception: decide whether the function should instead receive and return a value, maintain enclosing state, or intentionally a module name. This lesson focuses on the lookup consequence, while function interfaces belong in the adjacent lessons.

global and nonlocal are explicit rebinding choices

global name inside a function tells Python that references and assignments to name in that block use the module-level global namespace. It is not a general instruction to search outside; it specifically selects the defining module's global namespace. Because it changes how the block is compiled, it must appear before uses of that name in the block. Global state can be appropriate for narrowly scoped configuration or a deliberate shared counter, but its effects can be harder to trace than local state. nonlocal name is for a nested function that needs to rebind a name from an enclosing function. It does not target a module global, and it cannot create a brand-new enclosing binding. The named value must already be bound in an enclosing function scope; otherwise Python reports SyntaxError while compiling the code. This is useful for a : an inner function can keep access to a surrounding function's state after the outer call has produced it. Use nonlocal only when that persistent enclosing state is intentional.

Trace one lookup at a time

When tracing scope, first mark every assignment in each function block. Then, for the name being read, ask: is it local here? If not, is there an enclosing function binding? Then check the module global and built-ins. For a rebind, look for global or nonlocal before assuming an outer value changes. This mechanical method avoids two frequent errors: treating any outer name as automatically writable, and assuming that a global name saves a local variable that has not yet been bound. Write the lookup path beside each reference before predicting output; doing so turns an intuition problem into a checkable trace.

Eli, the EliExplains learning guide

Eli explains

The same idea, in plain words

Explain it like I’m 10

Imagine each function call is a desk with labeled drawers. To find a note called label, first open the drawer on the desk in front of you. If it is not there, look at desks belonging to functions wrapped around yours, then at the big desk for the whole file, and finally at the shared supply cabinet of built-in names. That is the lookup part of scope. Writing a new note changes the rule. If you write label = "local" at your desk, Python treats label as a label for your desk in that function. It does not silently replace a note at the big file desk. global explicitly says to write at the file desk. nonlocal says to write at the nearest surrounding function’s desk; that desk must already have the note.

Picture it like this

Scope is like looking for a labeled note through your desk, surrounding desks, the file desk, and then a shared supply cabinet.

Where the picture stops working

The desks do not describe physical storage, object mutation, or module imports; they only model name lookup and rebinding choices.

Worked example

This executed example has a module-level message and an enclosing message. outer creates the enclosing binding. Its nested inner uses nonlocal message, so its assignment changes outer's binding rather than creating an inner local. The module-level value remains untouched. A separate function, add_one_bad, contains an assignment to count; therefore count is local for that entire function. Its read occurs before that local binding, so the run raises UnboundLocalError.

message = "outer"

def outer():
    message = "enclosing"
    def inner():
        nonlocal message
        message = "changed enclosing"
    inner()
    return message

print(outer(), message)  # changed enclosing outer

count = 10
def add_one_bad():
    count = count + 1

try:
    add_one_bad()
except UnboundLocalError as error:
    print(type(error).__name__)  # UnboundLocalError

Key takeaway

Use LEGB to predict where a Python name is read. Then treat assignment as a separate decision: it is local by default, global targets the module namespace, and nonlocal targets an existing enclosing-function binding.

Quick check

3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.

Question 1 of 3foundational

Which sequence describes normal lookup for an unqualified name inside a nested function?

Choose an answer, then check it.
Question 2 of 3intermediate

A function contains total = total + 1 and no global or nonlocal statement. Why can its first call raise UnboundLocalError?

Choose an answer, then check it.
Question 3 of 3intermediate

In a nested function, what does nonlocal score require?

Choose an answer, then check it.
Practice all 5

Keep learning

Ready to build on this? Continue to the next lesson.

Practice this lesson
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related

You’ll learn to

  • Define scope and describe the LEGB lookup order.
  • Distinguish reading an outer name from rebinding a name locally.
  • Explain when global and nonlocal change assignment behavior.
  • Diagnose an UnboundLocalError caused by a local binding.
  • Apply name-resolution rules to a nested-function example.

Common mistakes

  • Assuming Python always reads a same-named global before a local.

    Mark assignments first; one in the function normally makes the name local throughout that block.

  • Using global merely to read a global value.

    Reading can use the normal lookup path; reserve global for deliberate global rebinding.

  • Using nonlocal for a module variable.

    nonlocal requires a previously bound name in an enclosing function; use global only when module rebinding is truly intended.

  • Treating UnboundLocalError as a missing-name error only.

    Check whether a later assignment caused Python to classify the name as local.

Easily confused

`global x` vs. `nonlocal x`

global selects the module namespace; nonlocal selects a previously bound enclosing-function name.

Reading an outer name vs. Rebinding a name

A read can follow normal lookup; assignment normally creates a local binding unless declared otherwise.

`NameError` vs. `UnboundLocalError`

A missing name raises NameError; using a function-local name before it is bound raises the more specific UnboundLocalError.

Key vocabulary

scope
The region of code in which a name can be accessed directly.
local scope
The names associated with one function call.
enclosing scope
A surrounding function's scope visible to a nested function.
global scope
The namespace at the top level of the module that defines a function.
built-in namespace
The namespace that supplies standard names such as len.
binding
Associating a name with a value in a namespace.
rebind
Make a name refer to a different value in its selected scope.
closure
A nested function that retains access to names from an enclosing function.
UnboundLocalError
The error raised when a function tries to use its local name before that name has been bound.

Sources & references

  1. The Python Tutorial — 9.2 Python Scopes and Namespaces — Python Software Foundation
  2. The Python Language Reference — Execution model (naming and binding) — Python Software Foundation

EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.

Researched 2026-08-19

Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.