Programming Essentials~15 min

Scope

A variable created inside a function only exists while that function runs — but a function can still read variables from outside it.

By the end of this lesson, you can

  • Explain why a variable created inside a function isn't visible outside it
  • Predict a NameError caused by using a name outside the scope where it was created
  • Explain why a function can read a variable from the surrounding scope, even without a parameter

Why it matters

Every function written so far has used variable names freely inside its own body without worrying whether those names existed anywhere else. That freedom comes from scope: the region of a program where a particular name is visible. Understanding it explains a specific, common error — using a name that “should” exist and getting a NameError — and clarifies exactly what a function can and can’t see.

Mental model

A variable created inside a function is local to it: it comes into existence when the function is called, and stops existing the moment the function returns. It was never visible outside the function to begin with — not because it was deleted, but because it never had meaning anywhere else.

Python
def set_total():
    total = 100
    print("Inside:", total)

set_total()
print("Outside:", total)
Output
Inside: 100
Traceback (most recent call last):
  File "example.py", line 6, in <module>
    print("Outside:", total)
NameError: name 'total' is not defined

total prints fine from inside set_total — but by the time control returns to the last line, total was never in scope there at all.

Trace it

Where total is visible as the program runs
Linetotal visible here?
inside set_total(), after total = 100Yes — local to this call
after set_total() returnsNo — total no longer exists
print("Outside:", total)No — raises NameError

A function can still read outer variables

PythonReading a variable from outside the function
DISCOUNT_RATE = 0.1

def apply_discount(price):
    return price * (1 - DISCOUNT_RATE)

print(apply_discount(100))
Output
90.0

apply_discount never received DISCOUNT_RATE as a parameter, yet it reads it without any error. A function can see and read any variable that already existed in the surrounding scope when it runs — the rule from the first example only applies to variables created inside the function.

Check your understanding

What happens when this runs? def greet(): message = "hi" return message greet() print(message)
Or reveal the answer without checking

Answer:Raises a NameError
message is local to greet — it exists only during that call, even though the function returned it. The returned value was never captured (greet()'s result was discarded, not assigned to anything outside), so message still doesn't exist outside the function.

Can a function read a variable that was defined outside it, without receiving it as a parameter?
Or reveal the answer without checking

Answer:Yes — a function can read any variable that already exists in the surrounding scope
Reading an outer-scope variable from inside a function works without any special syntax — the restriction is only on variables created inside the function, which don't exist outside it.

Practice: warm-up

Trace this program — for each print line, decide whether it succeeds and what it prints, or whether it raises a NameError.

LIMIT = 10

def check(value):
    result = value <= LIMIT
    return result

print(LIMIT)
print(check(5))
print(result)

Stuck? Reveal one hint at a time.

  1. Hint 1

    LIMIT is defined at the top level, outside any function — where is it visible from?

  2. Hint 2

    result is created inside check — does it exist anywhere once check has returned?

Reveal the trace

Try the problem yourself before reading this. There is often more than one reasonable approach — treat this as one worked example, not the only correct answer.

print(LIMIT)      -> prints 10 (LIMIT is at the top level, visible everywhere)
print(check(5))   -> prints True (5 <= 10)
print(result)     -> NameError — result only ever existed inside check()

Practice: apply it

This function is meant to report a running total, but the caller can never see it:

def add_to_total(previous_total, amount):
    total = previous_total + amount
    return total

add_to_total(0, 10)
print(total)
What's wrong with this code?
Or reveal the answer without checking

Answer:total is local to add_to_total and never existed outside it, so print(total) raises a NameError, even though the function itself ran without any problem
add_to_total(0, 10) runs fine and returns 10 — but that return value was never captured anywhere. total is local to the function, so print(total) has nothing to refer to outside it.

Modification challenge: fix this by keeping the running total outside the function, in a variable the function’s return value gets assigned back into — for example, total = add_to_total(total, 10), with add_to_total taking the current total as a parameter and returning the new one.

Summary

  • A variable created inside a function is local to it — it exists only while that call runs, and using its name outside the function raises a NameError.
  • A function can freely read a variable that already exists in the surrounding scope, without needing it as a parameter.
  • Reassigning an outer variable from inside a function isn’t as simple as reading one — that’s a sharper edge case beyond this lesson.
  • When a value needs to escape a function, return it and capture it in a variable outside — that’s the reliable way to make it visible where it’s needed.

Key terms