Computer Programming 1 (Python) • Functions & Modularity

Local vs. Global Scope — I can explain local vs global scope at a conceptual level and avoid unintended global variables.

Understanding where your variables live and die is the key to writing clean, bug-free Python functions.

A Python coding terminal with a program flow and laptop.
Inside this lesson 10 sections 5 questions 5 figures

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

Early FORTRAN programs used COMMON blocks, allowing many parts of a program to share the same variables. This worked for small programs but led to chaos in larger ones.

1960 • ALGOL Introduces Block Scope

The ALGOL 60 language introduced the idea that variables could belong to a specific block of code. A variable created inside a block would not exist outside it — the birth of local scope.

1972 • C Refines Scope Rules

The C programming language adopted and refined block-level scoping. Its clear distinction between local and global variables influenced nearly every language that followed.

1991 • Python Is Created

Guido van Rossum released Python with the LEGB rule (Local, Enclosing, Global, Built-in) for resolving variable names, giving programmers a clear and predictable scoping system.

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.

1

Scope

The region of your program where a particular variable name is recognized and can be accessed. Think of it as a variable's "territory" — it only exists within certain boundaries.
2

Local Scope

A variable created inside a function belongs to that function's local scope. It is born when the function runs and destroyed when the function finishes. No code outside the function can see it.
3

Global Scope

A variable created at the top level of a Python file — outside any function — lives in the global scope. It can be read from inside functions, but writing to it requires the special global keyword.
4

Name Resolution (LEGB Rule)

When Python encounters a variable name, it searches in this order: Local → Enclosing → Global → Built-in. It uses the first match it finds. This predictable search path prevents ambiguity.
✦

KEY TAKEAWAY

Think of a function like a classroom with its own whiteboard. Variables created inside the function are like notes written on that whiteboard — when class ends (the function returns), the whiteboard is erased. A global variable is like a poster hanging in the hallway that every classroom can read but shouldn't scribble on without permission.

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.

GLOBAL SCOPEmessage = "hello"count = 10LOCAL SCOPE — greet()name = "Alice"greeting = "Hi " + name↑ can READ global 'message'✗ cannot be seen outsideLOCAL SCOPE — add(a, b)a = 3b = 5result = a + b✗ cannot see 'name' or 'greeting'destroyed after returndestroyed after returnAFTER BOTH FUNCTIONS RETURNmessage = "hello" ✓ still exists (global)name → NameError ✗ gone (was local to greet)
The outer dashed box represents global scope. Each solid inner box is a function's local scope. After the functions finish, their local variables are erased, but the global variables remain.

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

Local→Enclosing→Global→Built−inLocal → Enclosing → Global → Built-in

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

Writing 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.

WITHOUT global keyword vs. WITH global keyword✓ SAFE — No Side EffectsGLOBALscore = 100def add_bonus():bonus = 20return score + bonusreads global, doesn't change itAFTER CALLscore still = 100 ✓Global stays untouched.Function is predictable.⚠ RISKY — Uses global keywordGLOBALscore = 100def add_bonus():global scorescore = score + 20modifies the global directly!AFTER CALLscore now = 120 ⚠Global was changed from afar.Harder to trace bugs.
Left panel: a safe function that reads the global variable but returns a new value without changing it. Right panel: a risky function using 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. 1

    Step 1 — Identify Global Variables

    The variable color = "blue" is assigned at the top level, outside any function, so it lives in global scope. The variable result is also assigned at the top level, so it is global too.
    Global variables: color, result
  2. 2

    Step 2 — Identify Local Variables Inside paint_room()

    Inside paint_room, the parameter size is automatically local. The assignment color = "red" creates a brand-new local variable called color — it does NOT change the global color. The variable area is also assigned inside the function, so it is local.
    Local variables in paint_room(): size, color, area
  3. 3

    Step 3 — Execute the Function Call

    When paint_room(10) is called, Python creates a local scope for the function. size gets the value 10. color is set to "red" locally. area becomes 10 × 10 = 100. The function returns 100.
    Return value: 100
  4. 4

    Step 4 — After the Function Returns

    The local scope of paint_room is destroyed. The local color ("red"), size, and area no longer exist. The global color is still "blue" because the function never touched it.
    print(color) outputs blue — print(result) outputs 100
💡

WHY THIS MATTERS

The global 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.

FeatureLocal VariablesGlobal Variables
LifetimeCreated when the function is called; destroyed when it returns.Exist from assignment until the program ends.
VisibilityOnly visible inside the function where they are created.Readable from anywhere; modifiable only with the global keyword.
SafetyVery safe — cannot be accidentally changed by other functions.Risky — any function using global can change the value unexpectedly.
DebuggingEasy to trace because you only need to look inside one function.Hard to trace because many functions could be modifying the value.
Best UseTemporary calculations, loop counters, intermediate results.Constants (values that never change), configuration settings.

Comparing local and global variable characteristics

🎯

DESIGN GUIDELINE

A good rule of thumb: prefer local variables and pass data through parameters and return values. Use global variables only for values that truly need to be shared across your entire program and that don't change, like 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 NowWhere It Leads
Local variables belong to a single functionClosures — nested functions that "remember" local variables from their enclosing function even after it returns.
Avoiding global variables through parameters and return valuesObject-Oriented Programming — classes bundle data (attributes) and functions (methods) together, giving data a clear "home" without using globals.
The LEGB name resolution ruleNamespaces and modules — Python uses namespaces to organize names across different files and libraries, extending the same idea of scoped lookup.
Functions as self-contained unitsPure 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

In your own words, explain the difference between a local variable and a global variable. Why does Python default to making variables inside functions local?
Show answer
A local variable is created inside a function and only exists while that function runs. A global variable is created outside all functions and exists for the entire program. Python defaults to local scope inside functions because it protects the rest of the program from accidental changes. If every function could freely modify global variables, a bug in one function could silently corrupt data used by other functions, making programs unpredictable and difficult to debug.

Question 2: BASIC CALCULATION

What does the following code print? Explain why. x = 5 def double(): x = 10 return x * 2 result = double() print(x) print(result)
Show answer
The code prints 5 and then 20. Inside the 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

The following code crashes with an error. Identify the error, explain why it happens, and fix the code without using the global keyword. total = 0 def add_to_total(value): total = total + value return total add_to_total(5)
Show answer
The code raises an 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

You are building a simple game where the player has a score. Write two functions: 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
Here is a clean solution: 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

A classmate argues: "Global variables are simpler because I don't have to pass anything around. Why should I bother with parameters and return values?" Write a short paragraph refuting this argument. Include at least two specific problems that arise from relying on global variables in a medium-sized program (50+ lines, 5+ functions).
Show answer
While global variables may seem simpler for tiny programs, they create serious problems as programs grow. First, when multiple functions modify the same global variable, any one of them could change its value in unexpected ways, creating bugs that are extremely difficult to trace — you have to read every function to figure out which one set the wrong value. Second, functions that depend on globals cannot be easily reused or tested in isolation; if you copy a function into a new program, you also have to remember to create all the global variables it secretly depends on. Third, using parameters and return values makes the inputs and outputs of a function explicit in its definition line, serving as built-in documentation. In a program with 5 or more functions, the small inconvenience of typing parameters saves hours of debugging time and makes the code far easier for teammates (or your future self) to understand.

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.

Varsity Tutors • Computer Programming 1 (Python) • Local vs. Global Scope