← Previous

Lesson 11 · Python

Scope

~30 min

1. Scope in Python

Have you ever created a variable inside a function, tried to print it outside that function, and hit a frustrating NameError? That happens because of Scope. Variable scope is the fundamental rulebook that determines where variables live, where they can be accessed, and how long they stay in memory during your program's execution.

Learning Objectives

  • Understand what scope is and why Python enforces variable isolation.
  • Master the LEGB Rule (Local, Enclosing, Global, Built-in).
  • Safely modify outer variables using the global and nonlocal keywords.
  • Avoid common scope pitfall errors like UnboundLocalError and variable shadowing.

2. What is Variable Scope?

In Python, variables aren't automatically available everywhere. The region of a program where a variable is recognized and accessible is called its scope. If a variable is defined inside a function, it exists only while that function is running.

Think of scope like security clearances in a building. Anyone inside a private office (Local scope) can look out into the main hallway (Global scope), but people standing in the hallway cannot look inside a locked private office.

Python code example:

def greet():
    message = "Hello from inside!"  # Local variable
    print(message)

greet()  # Output: Hello from inside!

# Trying to access 'message' outside the function will fail!
# print(message)  # NameError: name 'message' is not defined

3. The LEGB Rule: How Python Looks Up Variables

When you reference a variable name in Python, the interpreter searches for it in a specific, rigid order known as the LEGB Rule. It stops searching as soon as it finds the first match:

Letter Scope Level Description
L Local Names assigned inside a function or lambda expression.
E Enclosing Names in the local scope of any and all outer/nested functions.
G Global Names assigned at the top level of a module/file.
B Built-in Names pre-loaded into Python (e.g., print, len, range).

Python code example demonstrating LEGB:

x = "Global X"  # Global Scope

def outer_function():
    x = "Enclosing X"  # Enclosing Scope
    
    def inner_function():
        x = "Local X"  # Local Scope
        print(x)       # Python finds Local X first!
        
    inner_function()

outer_function()  # Output: Local X

4. The global Keyword

By default, you can read a global variable inside a function, but if you try to assign a new value to it, Python creates a new local variable instead. To explicitly tell Python that you want to modify a top-level global variable from inside a function, use the global keyword.

Python code example:

score = 0  # Global variable

def increase_score():
    global score  # Informs Python to use the global 'score'
    score += 10   # Modifies the global variable directly

print(score)      # Output: 0
increase_score()
print(score)      # Output: 10

5. The nonlocal Keyword

When working with nested functions (a function inside another function), the global keyword won't target the outer function's variable. To modify a variable in the enclosing function's scope, Python provides the nonlocal keyword.

Python code example:

def make_counter():
    count = 0  # Enclosing variable
    
    def increment():
        nonlocal count  # Targets 'count' in the outer make_counter function
        count += 1
        return count
        
    return increment

counter = make_counter()
print(counter())  # Output: 1
print(counter())  # Output: 2

6. Real World Example

Consider a user authentication session manager in a web application. You want to track whether a user is logged in globally while allowing temporary local operations during login verification.

# Global application state
CURRENT_USER = None
IS_AUTHENTICATED = False

def login_user(username, password):
    global CURRENT_USER, IS_AUTHENTICATED
    
    # Local variables for validation
    db_user = "alex_dev"
    db_pass = "supersecret123"
    
    if username == db_user and password == db_pass:
        CURRENT_USER = username
        IS_AUTHENTICATED = True
        print(f"Success: Welcome {CURRENT_USER}!")
    else:
        print("Error: Invalid credentials.")

# Attempting login
login_user("alex_dev", "supersecret123")

print(f"App State -> User: {CURRENT_USER}, Authed: {IS_AUTHENTICATED}")
# Output: App State -> User: alex_dev, Authed: True

7. Common Beginner Mistakes

⚠️ Watch out for these mistakes:

  • UnboundLocalError: Modifying a global variable inside a function without declaring global variable_name first causes Python to crash because it treats the variable as local before assignment.
  • Variable Shadowing (Overwriting Built-ins): Naming a local or global variable the same name as a Python built-in (e.g., list = [1, 2, 3] or str = "text") breaks the built-in function for the rest of your script.
  • Overusing Global Variables: Relying heavily on global variables makes code fragile, difficult to debug, and prone to unintended side effects. Pass arguments to functions instead!
  • Expecting Function Variables to Persist: Assuming variables created inside a function can be accessed after the function finishes running.

8. Code Examples

Here are handy patterns when working with variable scopes in Python:

# 1. Variable Shadowing Warning
# BAD: Overwriting the built-in len() function
# len = 10 
# print(len("hello"))  # TypeError: 'int' object is not callable

# GOOD: Use descriptive variable names
item_count = 10
print(len("hello"))    # Output: 5

# 2. Scope inside loops and conditionals
# Note: In Python, 'if' blocks and 'for' loops DO NOT create new scopes!
if True:
    status_code = 200

print(status_code)  # Output: 200 (Accessible globally!)
Interactive Practice

Mini Practice: Fixed Global Score Tracker

Define a global variable total_points = 100. Create a function add_bonus() that uses the global keyword to add 50 to total_points. Call the function and print total_points.

0% complete
Check when done
Quiz

Test Your Understanding

1. What order does Python follow when looking up variable names (LEGB rule)?

2. Which keyword allows a nested function to modify a variable in its outer (enclosing) function?

3. What happens if you try to modify a global variable inside a function without using `global`?

4. Do 'if' statements and 'for' loops create their own local scope in Python?

9. Challenge Project

Bank Account Closure Tracker: Create a closure function create_bank_account(initial_balance). Inside it, maintain a private balance variable. Define two inner functions: deposit(amount) and withdraw(amount) that use nonlocal to update and return the current balance. Return both functions so they can be called externally!

10. Key Takeaways

  • LEGB defines the exact lookup hierarchy: Local → Enclosing → Global → Built-in.
  • Variables created inside a function are Local and destroyed when the function ends.
  • Use global to modify top-level script variables from inside a function.
  • Use nonlocal to modify variables in nested outer functions.
  • Avoid naming your own variables after built-in Python functions like list, dict, or str.

🚀 Progression

You've mastered Python Scope! Next up, we will explore key concept modules in **Dictionaries & Key-Value Storage**!