SECTION 1
Historical Context & Motivation
In the earliest days of programming, every variable in a program was accessible from everywhere in the code. This might sound convenient at first, but imagine a huge program with thousands of lines — any part of the code could accidentally change a variable that another part depended on. These sneaky bugs were incredibly hard to track down. As programming languages evolved, language designers introduced the idea of scope, a set of rules that determines where a variable can be seen and used. Scope became one of the most important concepts in software engineering because it keeps different parts of a program from stepping on each other's toes.
1957 • FORTRAN and Shared Variables
1960 • ALGOL Introduces Block Scope
1972 • C Refines Scope Rules
1991 • Python Is Created
The central question that scope answers is straightforward: When I use a variable name, which variable am I actually referring to? Without clear scoping rules, two functions that both use a variable called count could silently overwrite each other's data. Understanding local and global scope in Python lets you write functions that are self-contained, predictable, and safe to reuse.
SECTION 2
Core Principles & Definitions
Before diving into code, you need to understand four foundational ideas that govern how Python decides which variable you mean when you write a name like x or total. These principles will guide every function you write.
Scope
Local Scope
Global Scope
global keyword.Name Resolution (LEGB Rule)
KEY TAKEAWAY
SECTION 3
Visual Explanation — Scope in Action
The diagram below illustrates how Python separates global scope from local scope. Notice that each function creates its own isolated box. Variables inside those boxes cannot leak out, and the global area sits around the outside.
Notice how the two function boxes are completely separate from each other. The variable result inside add() has no relationship to anything in greet(). Even if both functions happened to use a variable called x, each would have its own independent copy. This isolation is exactly what makes functions reliable and reusable.
SECTION 4
How Python Resolves Variable Names — The LEGB Rule
When Python encounters a variable name — say x — it does not simply look everywhere at once. Instead, it follows a strict search order known as the LEGB rule. Python checks four layers, stopping as soon as it finds a match.
LEGB SEARCH ORDER
L — variables assigned inside the current function. E — variables in any enclosing (outer) function (for nested functions). G — variables assigned at the top level of the module. B — names built into Python like print, len, range.
For this course, you will mostly deal with the Local and Global layers. The Enclosing layer matters when you write functions inside other functions, which is a more advanced topic. The Built-in layer is why you can use print() without importing anything — Python knows about it automatically.
The Assignment Rule
There is one critical rule that trips up beginners: if you assign to a variable anywhere inside a function, Python treats that variable as local to the entire function. This means even if a global variable with the same name exists, the function will create its own separate local copy. If you try to read the variable before the assignment line inside the function, you will get an UnboundLocalError because Python already decided the name is local, but it has not been assigned yet.
Common Pitfall
count = count + 1 inside a function when count is a global variable will crash with UnboundLocalError. The assignment makes Python treat count as local, but the right side tries to read it before the local version has a value.SECTION 5
The global Keyword and Unintended Side Effects
Python provides the global keyword to let a function modify a global variable instead of creating a local one. You place global variable_name at the top of the function body before using that variable. While this works, experienced programmers use it very sparingly because it introduces side effects — the function reaches outside its own scope and changes something in the wider program. This makes the code harder to debug and test.
global that modifies the global variable directly, creating a side effect.Best Practice: Pass and Return Instead
The preferred approach is to pass global data into a function as a parameter and get the answer back with a return statement. This way, the function doesn't secretly reach outside itself. For example, instead of using global score inside the function, you can write def add_bonus(current_score): return current_score + 20 and then call score = add_bonus(score) in the main program. The result is the same, but now the data flow is visible and explicit.
SECTION 6
Worked Example — Tracing Scope Step by Step
Let's trace through a short Python program and identify every variable's scope. Read the code below carefully, then follow each step.
Program to Trace
color = "blue"
def paint_room(size):
color = "red"
area = size * size
return area
result = paint_room(10)
print(color)
print(result)Tracing Variable Scope
- 1
Step 1 — Identify Global Variables
The variablecolor = "blue"is assigned at the top level, outside any function, so it lives in global scope. The variableresultis also assigned at the top level, so it is global too.Global variables:color,result - 2
Step 2 — Identify Local Variables Inside paint_room()
Insidepaint_room, the parametersizeis automatically local. The assignmentcolor = "red"creates a brand-new local variable calledcolor— it does NOT change the globalcolor. The variableareais also assigned inside the function, so it is local.Local variables in paint_room():size,color,area - 3
Step 3 — Execute the Function Call
Whenpaint_room(10)is called, Python creates a local scope for the function.sizegets the value 10.coloris set to"red"locally.areabecomes 10 × 10 = 100. The function returns 100.Return value:100 - 4
Step 4 — After the Function Returns
The local scope ofpaint_roomis destroyed. The localcolor("red"),size, andareano longer exist. The globalcoloris still"blue"because the function never touched it.print(color)outputs blue —print(result)outputs 100
WHY THIS MATTERS
color survived the function call unchanged because the assignment inside paint_room() created a completely separate local variable. This is Python's default safety mechanism: assignments inside functions stay local unless you explicitly say otherwise with global.SECTION 7
Local vs. Global — Strengths and Limitations
Neither local nor global variables are inherently "bad," but they serve very different purposes. Understanding their strengths and limitations helps you make smart choices about where to store data in your programs.
| Feature | Local Variables | Global Variables |
|---|---|---|
| Lifetime | Created when the function is called; destroyed when it returns. | Exist from assignment until the program ends. |
| Visibility | Only visible inside the function where they are created. | Readable from anywhere; modifiable only with the global keyword. |
| Safety | Very safe — cannot be accidentally changed by other functions. | Risky — any function using global can change the value unexpectedly. |
| Debugging | Easy to trace because you only need to look inside one function. | Hard to trace because many functions could be modifying the value. |
| Best Use | Temporary calculations, loop counters, intermediate results. | Constants (values that never change), configuration settings. |
Comparing local and global variable characteristics
DESIGN GUIDELINE
PI = 3.14159 or MAX_LIVES = 3. If you find yourself reaching for the global keyword frequently, it is a signal to redesign your functions to use parameters and return values instead.SECTION 8
Connection to Advanced Concepts
The scoping concepts you've learned here form the foundation for several advanced programming topics. As you continue in computer science, you'll see these ideas expand and become even more powerful.
| What You Know Now | Where It Leads |
|---|---|
| Local variables belong to a single function | Closures — nested functions that "remember" local variables from their enclosing function even after it returns. |
| Avoiding global variables through parameters and return values | Object-Oriented Programming — classes bundle data (attributes) and functions (methods) together, giving data a clear "home" without using globals. |
| The LEGB name resolution rule | Namespaces and modules — Python uses namespaces to organize names across different files and libraries, extending the same idea of scoped lookup. |
| Functions as self-contained units | Pure functions and functional programming — functions that have no side effects and depend only on their inputs, making programs easier to test and reason about. |
From scope basics to advanced programming concepts
You don't need to master these advanced topics right now, but knowing they exist helps you see the bigger picture. Every time you practice keeping your variables local, you are building habits that will serve you in AP Computer Science, college-level courses, and professional software development.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
Show answer
Question 2: BASIC CALCULATION
x = 5
def double():
x = 10
return x * 2
result = double()
print(x)
print(result)Show answer
double() function, x = 10 creates a new local variable x that shadows the global x. The function returns 10 × 2 = 20, which is stored in result. The global x was never changed, so it still holds 5.Question 3: INTERMEDIATE
global keyword.
total = 0
def add_to_total(value):
total = total + value
return total
add_to_total(5)Show answer
UnboundLocalError. Because total appears on the left side of an assignment inside the function, Python treats it as a local variable for the entire function. However, the right side total + value tries to read this local total before it has been assigned a value, causing the crash. To fix it without global, pass the current total as a parameter: def add_to_total(current_total, value): return current_total + value. Then call it with total = add_to_total(total, 5).Question 4: APPLIED
earn_points(current_score, points) that returns the updated score after earning points, and lose_life(current_lives) that returns the number of lives after losing one. Neither function should use the global keyword. Show how you would call them from the main program.Show answer
def earn_points(current_score, points):
new_score = current_score + points
return new_score
def lose_life(current_lives):
return current_lives - 1
# Main program
score = 0
lives = 3
score = earn_points(score, 50)
score = earn_points(score, 30)
lives = lose_life(lives)
print("Score:", score) # 80
print("Lives:", lives) # 2
Both functions take the current value as a parameter and return the updated value. The main program explicitly updates score and lives with the return values, making the data flow clear and traceable.Question 5: CRITICAL THINKING
Show answer
SUMMARY
Lesson Summary
Summary
Scope determines where a variable can be accessed in your Python program. A local variable is created inside a function and exists only while that function runs — it is destroyed when the function returns. A global variable is created outside all functions and persists for the entire program. Python follows the LEGB rule (Local → Enclosing → Global → Built-in) to resolve variable names, always starting with the most local scope.
Assigning to a variable inside a function automatically makes it local, even if a global variable with the same name exists. To modify a global from inside a function, you must declare it with the global keyword — but this is generally discouraged because it creates side effects that make bugs harder to find. The best practice is to pass data through parameters and return values, keeping your functions self-contained, predictable, and easy to reuse.