Scope: global, nonlocal & LEGB

Scope is the set of rules that decides which variable a name refers to, and Python resolves it with the LEGB rule — searching Local, then Enclosing, then Global, then Built-in scopes and using the first match it finds.

Learn Scope: global, nonlocal & LEGB in our free Python course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Understanding scope is the difference between confidently sharing state and being baffled by a mysterious UnboundLocalError . Once you know how Python looks up names, the global and nonlocal keywords stop feeling like magic.

When Python sees a name, it searches four scopes in order and stops at the first match: L ocal → E nclosing → G lobal → B uilt-in. Here all four hold an x , and each scope sees the closest one:

This is why you can call len() anywhere — it's found in the Built-in scope, the last stop on the search.

Reading a global needs nothing special. But reassigning one from inside a function requires the global keyword — otherwise the assignment quietly creates a new local instead:

Without global counter , the line counter += 1 would try to read a local counter that doesn't exist yet — and crash. The keyword says "operate on the outer one."

nonlocal is global 's cousin for enclosing scopes. It lets an inner function reassign a variable in the function that wraps it — the foundation of closures that remember state between calls:

This one bites everyone. If a function assigns to a name anywhere in its body, Python marks that name local for the whole function — even on lines before the assignment. Reading it first then fails:

Why can you list.append() to a global list without the global keyword, but can't reassign it? Because mutating an object and rebinding a name are different operations:

Fix this counter closure so it actually increments. Replace each ___ , then run it.

✅ To touch an enclosing function's variable, use nonlocal x , not global x .

✅ Don't name variables after built-ins ( list , dict , str , id , sum ). A local name shadows the built-in for that scope.

Build a closure make_averager() that remembers every number it's given and returns the running average. Use nonlocal to track the total and count.

Lesson complete — scope holds no mystery now!

You can trace any name through the LEGB order, reassign globals with global , build stateful closures with nonlocal , diagnose the UnboundLocalError trap, and tell mutation apart from rebinding. That's a superpower for reading and debugging real code.

🚀 Up next: Custom Exceptions & Exception Chaining — design robust error handling.

Practice quiz

What does the LEGB rule stand for, in search order?

  • Loop, Else, Generator, Block
  • Late, Early, Global, Bound
  • Local, Enclosing, Global, Built-in
  • Local, External, Global, Base

Answer: Local, Enclosing, Global, Built-in. Python resolves a name by searching Local, then Enclosing, then Global, then Built-in scopes.

Given x='global', an outer with x='enclosing', and inner with x='local', what does inner print for x?

  • local
  • global
  • enclosing
  • UnboundLocalError

Answer: local. LEGB stops at the first match — inner's own Local x wins.

When do you need the global keyword inside a function?

  • To read a module-level variable
  • To call a built-in function
  • Never
  • To reassign (rebind) a module-level variable

Answer: To reassign (rebind) a module-level variable. Reading a global needs nothing; rebinding one from inside a function requires 'global'.

What does nonlocal target?

  • The module/global scope
  • The nearest enclosing function's scope
  • The built-in scope
  • A brand-new local

Answer: The nearest enclosing function's scope. nonlocal lets an inner function reassign a variable in the function that wraps it.

A make_counter closure uses 'nonlocal count; count += 1'. What do three calls print?

  • 1 2 3
  • 1 1 1
  • 0 1 2
  • 3 3 3

Answer: 1 2 3. nonlocal makes the count persist and increment across calls, giving 1, 2, 3.

Why does reading a name then assigning it later in the same function raise UnboundLocalError?

  • The name is misspelled
  • Python forbids reassignment
  • An assignment anywhere makes the name local for the WHOLE function
  • The global was deleted

Answer: An assignment anywhere makes the name local for the WHOLE function. Because assignment anywhere marks the name local everywhere, the earlier read hits an uninitialized local.

items=[1,2,3] is global. A function calls items.append(4) with no 'global'. What is items afterward?

append MUTATES the existing object — no assignment, no local — so the global list is changed.

config={'v':1} is global. A function does config={'v':2} with no 'global'. What is the global config after?

  • {'v': 2}
  • {}
  • UnboundLocalError
  • {'v': 1}

Answer: {'v': 1}. Rebinding creates a NEW local config; the global is untouched, staying {'v': 1}.

To update an enclosing function's variable from an inner function, you use...

  • global
  • nonlocal
  • static
  • extern

Answer: nonlocal. nonlocal targets the enclosing function; global would wrongly look for a module-level name.

Why can you call len() from any scope without importing it?

  • It is a keyword
  • It is automatically local
  • It lives in the Built-in scope, the last LEGB stop
  • It is enclosing-scoped

Answer: It lives in the Built-in scope, the last LEGB stop. Built-ins like len, print, and range are found in the B scope, searched last in LEGB.