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

By

Introduction

Understanding Python scope is essential for writing clean, predictable code. The LEGB rule—Local, Enclosing, Global, Built-in—defines how Python resolves variable names. This guide will walk you through the hierarchy step by step, show you how to inspect and modify scopes, and help you avoid common pitfalls. By the end, you'll be able to confidently navigate scope boundaries in your Python programs.

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

What You Need

  • A Python interpreter (version 3.x recommended)
  • Basic understanding of functions and variable assignment
  • Willingness to experiment with code examples

Step-by-Step Instructions

Step 1: Grasp the Concept of Scope

Scope determines where a variable name is accessible. Python uses lexical (static) scoping: the scope is determined at compile time based on the structure of the code. Start by creating a simple variable at the top level of a script and try to access it inside a function. Note that variables defined outside functions are global by default.

Step 2: Learn the LEGB Order

When Python looks up a name, it searches in this order:

  1. Local – inside the current function
  2. Enclosing – any and all enclosing functions (from innermost outward)
  3. Global – the top-level scope of the module
  4. Built-in – names in the builtins module (like print, len)

The search stops at the first match. If nothing is found, a NameError is raised.

Step 3: Identify Local Scope

Any variable assigned inside a function (including parameters) exists in that function's local scope. Write a function that defines a variable and returns it. Try accessing the same variable outside the function—it will raise a NameError because it's local.

def my_func():
    x = 10  # local to my_func
    return x

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

Step 4: Understand Enclosing Scope (Nested Functions)

When you have a function inside another function, the inner function can access variables from the enclosing function's scope (but not the other way around). This is the E in LEGB. Create an outer function with a variable, then an inner function that uses that variable. Notice that the inner function can read the variable without any special declaration.

def outer():
    y = 20
    def inner():
        print(y)  # accesses y from enclosing scope
    inner()

outer()  # prints 20

Step 5: Work with Global Scope

Variables defined at the module level are global. They can be read inside functions without any special keyword. But if you try to assign to a global variable inside a function, Python creates a new local variable unless you use the global statement. To modify a global variable from within a function, declare it with global.

z = 100

def modify_global():
    global z
    z = 200

modify_global()
print(z)  # 200, because global was used

Step 6: Explore Built-in Scope

Built-in names are always available. Examples: print, len, range. You can shadow a built-in by naming one of your variables the same, but it's not recommended. To see the built-in scope, you can inspect dir(__builtins__). Never override built-ins unless you have a very good reason.

Step 7: Use the global Statement

The global statement tells Python that a variable name should be treated as referring to the global scope, even if assigned inside a function. Use it sparingly—excessive global variables can make code hard to debug. Only use global when you truly need to modify a module-level variable from within a function.

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

Step 8: Use the nonlocal Statement

The nonlocal statement works similarly but for enclosing (non-global) scopes. It allows you to assign to a variable in an enclosing function scope from inside a nested function. Without nonlocal, assignment in the inner function creates a new local variable instead.

def outer():
    a = 1
    def inner():
        nonlocal a
        a = 2
    inner()
    print(a)  # 2, because nonlocal allowed modification

outer()

Step 9: Test Your Knowledge with Examples

Now practice by writing small programs that mix different scopes. Try to predict the output of code snippets. For example:

def func1():
    x = 5
    def func2():
        x = 10
        print(x)
    func2()
    print(x)

func1()  # What will be printed?

Answer: 10 then 5 – because x in func2 is local, not the same as x in func1.

Tips and Common Pitfalls

  • Shadowing built-ins: Avoid naming variables list, dict, str, etc. Use slightly different names instead.
  • Unintended globals: If you forget global and assign a variable inside a function, Python treats it as a new local. This can cause bugs when you think you're updating a global.
  • Closures: When you return a nested function that references enclosing variables, the variable values are preserved in a closure. This is powerful but can lead to memory leaks if not managed.
  • Debugging scope issues: Use print(locals()), print(globals()) or a debugger to inspect which variables are in scope at any point.
  • Readability: Limit the depth of nested functions. Deep nesting makes the LEGB rule harder to follow.
  • Practice with quizzes: After learning, challenge yourself with a short quiz to solidify the concepts. Many online resources offer exercises on Python scope.

Remember, mastering scope takes practice. Start with simple examples and gradually introduce nested functions, global modifications, and closures. The LEGB rule is your roadmap—use it to navigate variable resolution with confidence.

Tags:

Related Articles

Recommended

Discover More

How to Set Up and Use Your MOFT MagSafe Wallet with Find My10 Key Insights from Microsoft's Forrester Wave Leadership in Sovereign Cloud PlatformsHidden Dual Role of Fat Cell Protein Challenges Long-Held Views on ObesityWhy I Switched from Raspberry Pi to $5 ESP32 for Smart Home AutomationNYT Strands Game #791 Solved: Sunday, May 3 Spangram Revealed – Hints and Answers Now Live