Kousa4 Stack
ArticlesCategories
Programming

Mastering Python Scope: A Step-by-Step Guide to the LEGB Rule

Published 2026-05-13 07:15:25 · Programming

Introduction

Understanding how Python resolves names is crucial for writing bug‑free code. At the heart of this is the LEGB rule—a fundamental concept that governs variable scope in Python. This guide will walk you through each component of scope: Local, Enclosing, Global, and Built-in. By following these steps, you’ll learn exactly how Python looks up names and how to use the global and nonlocal statements to control scope. Whether you’re debugging an unexpected NameError or writing modular functions, mastering scope is a must.

Mastering Python Scope: A Step-by-Step Guide to the LEGB Rule
Source: realpython.com

What You Need

  • A working Python environment (version 3.x recommended)
  • A code editor or IDE
  • Basic familiarity with Python functions and variables
  • Willingness to test code snippets as you follow along

Step 1: Understand What Scope Means in Python

Scope defines the region of a program where a particular variable is accessible. In Python, scope is determined by the location of variable assignments and function definitions. The LEGB rule dictates the order Python searches for names: Local, then Enclosing, then Global, and finally Built-in. Grasping this hierarchy is the first step to controlling name resolution.

Step 2: Learn the LEGB Rule

The LEGB rule is not just an acronym—it’s the search order Python uses when you reference a name. Here’s the breakdown:

  • Local: Names defined inside the current function or class method.
  • Enclosing: Names defined in the function that wraps the current one (nested functions).
  • Global: Names defined at the top level of a module or script.
  • Built-in: Pre‑defined names like print(), len(), and range().

Python checks each scope in that exact order. If a name isn’t found in any of these, you get a NameError. Understanding this order helps you predict which variable will be accessed.

Step 3: Explore Local Scope

Begin with local scope. Write a simple function that uses a variable:

def greet():
message = "Hello"
print(message)

greet()
# print(message) # NameError: message is not defined outside

Notice that message exists only inside greet(). Outside the function, it’s invisible. This is local scope. Start experimenting by creating multiple functions with the same variable name to see they don’t interfere.

Step 4: Explore Enclosing Scope (Nested Functions)

When you define a function inside another function, the inner function can access variables from the outer function. This is the enclosing scope. Consider:

def outer():
x = "outer variable"
def inner():
print(x) # x is from enclosing scope
inner()

outer()

The inner function sees x because it’s defined in its enclosing scope. Try modifying x from the inner function—you’ll discover you cannot assign to it without the nonlocal statement.

Step 5: Explore Global Scope

Global scope includes names defined at the module level. Any function can read global variables, but writing to them requires the global keyword.

counter = 0

def increment():
global counter
counter += 1

increment()
print(counter) # 1

Without global counter, Python would treat counter as a local variable and raise an UnboundLocalError. Experiment by omitting the global declaration to see the error.

Mastering Python Scope: A Step-by-Step Guide to the LEGB Rule
Source: realpython.com

Step 6: Explore Built-in Scope

Python provides many built‑in functions like print(), len(), and sum(). These reside in the built‑in scope. You can see the full list with dir(__builtins__). Be careful not to shadow built‑ins by creating variables with the same name (e.g., len = 5). This will hide the original len() function and cause errors later.

Step 7: Use global and nonlocal to Reach Across Scope Boundaries

When you need to modify a variable from an enclosing or global scope from inside a nested function, use these statements:

  • global – for variables in the module’s global scope.
  • nonlocal – for variables in the nearest enclosing scope (skipping the global level).

Example with nonlocal:

def outer():
x = 10
def inner():
nonlocal x
x = 20
inner()
print(x) # 20

outer()

Without nonlocal x, the assignment would create a new local variable. Test this by removing the declaration and seeing the output change.

Step 8: Practice with Real‑World Examples

To solidify your understanding, create scenarios that combine multiple scopes. For instance, write a function that uses a global counter, an enclosing variable, and a local temporary variable. Try to predict the output before running the code. Debug with print() statements or use Python’s globals() and locals() functions to inspect current scopes. Repeat until you can trace the LEGB search naturally.

Tips & Best Practices

  • Prefer local variables whenever possible—they keep code modular and reduce side effects.
  • Avoid shadowing built‑ins like list or input with your own variables.
  • Use global sparingly; too many globals can lead to spaghetti code.
  • Leverage nonlocal only when you truly need to modify an enclosing variable from a nested function.
  • Use the built‑in functions dir(), globals(), and locals() to explore scopes during debugging.
  • Consider signing up for 🐍 Python Tricks—short, insightful tips delivered every few days to sharpen your Python skills.

Mastering the LEGB rule is a milestone in your Python journey. By following these steps and practicing regularly, you’ll gain the confidence to write clear, predictable code that behaves exactly as you intend.