This One Python Rule Will Save You Hours of Debugging

By Nuno Bispo
5 min read

Table of Contents

I once spent several days debugging a Python issue where variables had unexpected values.

My code looked correct, individual functions worked as expected, and tests passed. But when everything ran together, variables took on values I never assigned, and functions behaved differently than I expected.

The issue was that I didn't understand how Python finds variables.

Specifically, I didn't know the LEGB rule, the systematic way Python searches for variable names across different scopes. Once I learned it, scope-related bugs became much easier to identify and fix.

This article will teach you the LEGB rule clearly, directly, with real examples. No jargon. No abstract explanations that leave you more confused.

You'll learn exactly how Python resolves variable names, why your code behaves the way it does, and how to avoid the scope-related bugs that trip up so many developers.


What Is the LEGB Rule?

The LEGB rule is Python's search strategy for finding variables. Think of it as a four-step checklist Python follows every time it sees a variable name in your code.

LEGB stands for the four scopes Python checks, in this specific order:

  1. L – Local: Variables defined inside the current function
  2. E – Enclosing: Variables from outer functions (in nested functions)
  3. G – Global: Variables defined at the module level
  4. B – Built-in: Python's built-in functions and constants

Python searches these scopes from top to bottom, stopping at the first match. If a variable exists in multiple scopes, Python uses the one it finds first in this order, which is why local variables can "hide" global ones.

Python LEGB Rule WorkflowLEGB

If Python doesn't find the variable name in any of these four scopes, you get a NameError.


Why the LEGB Rule Matters

You might be thinking: "My code works fine. Why do I need to learn another rule?"

Here's the thing: LEGB isn't optional knowledge. Every time Python executes your code, it's using this rule to resolve every variable name. When you don't understand it, you're flying blind, and that's when bugs creep in.

Knowing the LEGB rule gives you:

  • Faster debugging: When a variable has the wrong value, you'll know exactly where Python found it
  • Clearer code: You'll write functions with explicit, predictable behaviour
  • Fewer mistakes: You'll avoid accidentally shadowing global variables or built-in functions
  • Better design choices: You'll know when (and when not) to use global and nonlocal

Without understanding LEGB, your Python code works more by accident than by design. With it, you write code that behaves exactly how you intend.


Local Scope (L)

The local scope is the innermost scope. It contains variables defined inside a function.

Example

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

greet()

Here, message is a local variable. It only exists while the function is running.

Trying to access it outside the function will fail:

print(message)  # NameError: name 'message' is not defined

Key Points About Local Scope

  • Created when a function is called
  • Destroyed when the function returns
  • Has the highest priority in the LEGB lookup order

If a variable exists locally, Python will not look elsewhere.


Enclosing Scope (E)

The enclosing scope exists when you have nested functions, meaning a function inside another function.

This scope contains variables from the outer function, but not the global scope.

Example

def outer():
    name = "Alice"

    def inner():
        print(name)

    inner()

outer()

Here’s what happens:

  • inner() looks for name
  • It doesn’t find it in its local scope
  • Python checks the enclosing scope (outer)
  • name is found and printed

Global Scope (G)

The global scope contains variables defined at the top level of a module (outside any function).

Example

pi = 3.14

def area(radius):
    return pi * radius ** 2

print(area(5))

Here:

  • pi is not local to area
  • It’s not in an enclosing scope
  • Python finds it in the global scope

Important Notes About Global Scope

  • Each module has its own global scope
  • Global variables are shared across all functions in the module
  • Overusing globals makes code harder to test and maintain

Built-in Scope (B)

The built-in scope contains names that are always available in Python, such as:

  • print
  • len
  • range
  • int
  • list

These names live in the builtins module.

Example

numbers = [1, 2, 3]
print(len(numbers))

Python resolves len by checking each scope in LEGB order until it finds the name. Since len isn't defined locally, in an enclosing function, or globally, Python finds it in the built-in scope.


Important Scope Rules

It’s important to understand a few practical scope rules that often surprise developers. These rules aren’t theoretical edge cases, they directly affect how your code behaves and are a common source of subtle bugs if you’re not aware of them.

Loops Don't Create New Scopes

Unlike some languages, Python loops do not create a new scope. Variables assigned inside loops belong to the surrounding scope.

x = 10

for i in range(3):
    x = i

print(x)  # 2 (not 10!)

The loop variable i and any assignments inside the loop affect the enclosing scope. This is why x ends up as 2 (the last value assigned in the loop).

List Comprehensions Do Create Scopes

However, list comprehensions do have their own local scope in Python 3:

x = 10
values = [x for x in range(5)]
print(x)  # 10 (unchanged!)

The x inside the comprehension is separate from the outer x. This prevents the loop variable from "leaking" into your surrounding code, which is generally what you want.


Best Practices for Working with Scope

  • Keep functions small and focused
  • Avoid global variables
  • Pass values explicitly via parameters
  • Use descriptive variable names to prevent collisions

Final Thoughts

The LEGB rule isn't just theory, it's the mechanism Python uses every single time it resolves a variable name. Understanding it transforms confusing bugs into obvious scope issues.

When you understand how Python searches for variables, you gain a powerful advantage: you can debug faster by knowing exactly where Python will find (or fail to find) a variable, and you can write clearer, more predictable code.

The next time a variable behaves unexpectedly, remember: Python is following the LEGB rule. Trace through the scopes, and you'll find the answer.


Want to Go Deeper?

This article covers the essentials, but there's so much more to master. Want a complete guide with advanced examples, common pitfalls, and practical patterns?

Get my free PDF guide on Python Variable Scope, it includes everything you need to master LEGB, closures, decorators, and never waste hours debugging scope issues again.


Follow me on Twitter: https://twitter.com/DevAsService

Follow me on Instagram: https://www.instagram.com/devasservice/

Follow me on TikTok: https://www.tiktok.com/@devasservice

Follow me on YouTube: https://www.youtube.com/@DevAsService

Tagged in:

Python, LEGB, Scope

Last Update: January 16, 2026

About the Author

Nuno Bispo Netherlands

Building better devs, one post at a time. 💻 Practical tips, pro insights, and tools that actually work. Read the blog today.

View All Posts