A. Programming Concepts and Skills · Arrays and SubprogramsVariable Scope: Local and Global
A3.2 A4.2 A4.1About 65 minutes
Learning goals- I can tell whether a variable is local or global, and where in a program it can be used.
- I can predict the output when a local variable has the same name as a global one.
- I can explain the UnboundLocalError and fix it, preferably with parameters and return values instead of global.
- I can follow the convention of global CONSTANTS in capitals and keeping other data local.
Words to know
scope
The part of a program where a variable name can be used.
local variable
A variable created inside a function (including its parameters). It can only be used inside that function and disappears when the function returns.
global variable
A variable created at the top level of a file, outside every function. Any function can read it.
lifetime
How long a variable exists while the program runs. A local variable lives only during one call.
shadowing
When a local variable has the same name as a global one, so the global is hidden inside that function.
global (keyword)
A statement inside a function, e.g. global count, that makes assignments to that name change the global variable.
constant
A value that should not change while the program runs. By convention its name is in CAPITALS, e.g. TAX_RATE.
What happens in a function stays in a function
Two students on a group project both write a function, and both use a variable called total. Will they overwrite each other's totals? No, and that is one of the best things about functions. Each function has its own private set of variable names, called its local scope. The curriculum asks you to write subprograms that use appropriate variable scope (local, global). This lesson explains exactly what that means and why good programmers keep almost everything local.
Local variables
A variable is local to a function if it is created inside the function: by an assignment in the body, or as a parameter.
- It can only be used inside that function. Using it outside gives NameError.
- It is created fresh on each call and destroyed when the function returns. This is its lifetime.
- Two functions can each have a local variable with the same name; they are completely separate.
Global variables
A variable created at the top level of the file (not inside any function) is global. It exists for the whole run, and any function can read it.
Scopes nest like boxes. Code inside a function can read names in its own box and in the global box around it, but not names in another function's box. Both functions have a local called total; they never interfere.TAX_RATE = 0.13 # global constant (HST in Ontario)
def subtotal(prices):
total = 0 # local to subtotal
for p in prices:
total += p
return total
def with_tax(amount):
total = amount * (1 + TAX_RATE) # a different local total
return round(total, 2)
cart = [4.99, 12.50, 3.25]
s = subtotal(cart)
print(round(s, 2))
print(with_tax(s))
Output: 20.74 and 23.44. subtotal and with_tax each have their own total. with_tax reads the global constant TAX_RATE (13% HST, Ontario's sales tax rate on most items). Notice that the global variable s has nothing to do with any local variable. (round(s, 2) is there because adding floats such as 4.99 can leave a tiny binary error: the unrounded sum prints as 20.740000000000002.)
The lifetime of a local variable. total inside subtotal is created when the call starts and disappears at return. The next call makes a brand-new total starting from 0.Same name, different variable: shadowing
If a function assigns to a name, Python treats that name as local for the whole function, even if a global with the same name exists. The local shadows (hides) the global inside the function.
x = 10
def show():
x = 99 # a NEW local x; the global x is untouched
print("inside:", x)
show()
print("outside:", x)
Output: inside: 99 and outside: 10. Assigning x = 99 inside show created a local x. The global x was never touched.
The UnboundLocalError
Because of that rule, this common mistake fails:
count = 0 at the top, then a function whose body is count += 1.
The function assigns to count, so count is local in the whole function. But count += 1 needs the old value of the local count, and it does not have one yet. Python 3.13 reports:
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value
(older versions say local variable 'count' referenced before assignment). There are two fixes.
count = 0
def add_visitor():
global count # use the global count, don't make a local one
count += 1
add_visitor()
add_visitor()
print(count)
Fix 1: the global statement. Output: 2. It works, but now the function silently changes data outside itself.
def add_visitor(count):
return count + 1
count = 0
count = add_visitor(count)
count = add_visitor(count)
print(count)
Fix 2 (usually better): pass the value in as a parameter and return the new value. Output: 2. The function now depends only on its parameters, so you can test it on its own: add_visitor(41) must return 42.
Professional conventions for scope
- Keep variables local whenever you can. Data goes in through parameters and comes out through return.
- Global constants are fine and common. Write them in CAPITALS at the top of the file:
TAX_RATE = 0.13, MAX_PLAYERS = 20. Capitals tell readers "do not change this". - Avoid
global for ordinary data. When many functions can change the same global variable, a bug in one shows up in another, and tracing becomes very hard. - Use different, meaningful names even when shadowing is allowed. It makes tracing easier.
Worked exampleExample 1: Trace the scopes
Predict the output.
n = 5
def f(n):
n = n * 2
return n
def g():
return n + 1
print(f(3), g(), n)
f(3): the parameter n is local to f, so it starts at 3, becomes 6, and 6 is returned. The global n is still 5.g(): g has no local n (it never assigns n), so it reads the global n = 5 and returns 6.- The last value printed is the global n, which is still 5.
Worked exampleExample 2: Fix the NameError
This program crashes with NameError: name 'average' is not defined. Explain and fix it.
def find_average(values):
average = sum(values) / len(values)
find_average([70, 80, 90])
print(average)
average is local to find_average. When the function returns, it disappears, and the global scope never had a variable called average.- The fix is not
global. Return the value and store it in the caller: def find_average(values):
return sum(values) / len(values)
average = find_average([70, 80, 90])
print(average)
It prints 80.0. A function's results should leave through return.
Just for funLocal variables are like what happens at a sleepover: it exists only for that night, nobody outside ever sees it, and by morning it's all gone. (Global variables are the house rules on the fridge.)
Hands-on activityScope with sticky notes
You need: 3 sheets of paper, sticky notes in two colours if possible, a pen, and a computer with Python.
- Label one big sheet GLOBAL and two smaller sheets f and g. Put the small sheets on top of the big one, like the scope diagram.
- Take the program from Example 1. Each time a variable is created, write it on a sticky note with its value and stick it on the sheet for its scope. When a function returns, peel off all the notes on its sheet: their lifetime is over.
- When code needs a name, look on the current sheet first, then on GLOBAL.
- Now write your own short program that includes a shadowed name, and challenge a family member to predict the output with the sheets before you run it.
What to look for: notes for parameters go on the function's sheet, and the student removes them at return.
Your turn
1Is a function's parameter local or global?
2Predict the output:
def f():
y = 3
return y
f()
print(y)
NameError: name 'y' is not defined. y is local to f and no longer exists after f returns. (The returned 3 was also thrown away.)
3Predict the output:
a = 1
def f():
a = 2
return a
print(f(), a)
2 1. The a inside f is a new local variable that shadows the global.
4Predict the output:
RATE = 3
def cost(n):
return n * RATE
print(cost(4))
12. cost can read the global constant RATE.
5Why does this crash? total = 0 then def add(x): total += x.
Because add assigns to total, total is local in add, so total += x reads a local that has no value yet: UnboundLocalError.
6Rewrite add from the last question without using global.
def add(total, x): return total + x, and call it as total = add(total, 5).
7Why are constants written in capitals?
It is a convention that tells readers the value should not change while the program runs.
More practice: warm-up
1Where is a global variable created?
At the top level of the file, outside every function.
2When is a local variable destroyed?
When the function returns.
3Can two different functions both have a local variable called i?
Yes. They are separate variables.
4Which keyword lets a function assign to a global variable?
5Name one global constant you might use in a program about Ontario sales tax.
For example TAX_RATE = 0.13.
More practice: on your own
1Predict the output:
x = 5
def double():
return x * 2
x = 7
print(double())
14. The function reads the global x when it is called, and by then x is 7.
2Predict the output:
def f(a):
a = a + 1
b = a * 2
return b
a = 10
b = f(a)
print(a, b)
10 22. Inside f, the local a becomes 11 and the local b is 22. The global a is unchanged; the global b gets the returned 22.
3A program uses a global list scores and a function def add_score(s): scores.append(s). It works, with no global statement. Why?
The function does not assign to the name scores; it only calls a method on the list it finds in the global scope. Changing the list's contents is allowed. (Passing scores as a parameter would still be clearer.)
4List two reasons why using many global variables makes a program hard to debug.
Any function might change them, so when a value is wrong you must check every function; and functions that depend on globals cannot be tested on their own with chosen inputs.
5Predict the output:
total = 100
def spend(amount):
global total
total = total - amount
spend(30)
spend(25)
print(total)
45. Both calls change the global total: 100 − 30 − 25.
Challenge
1Predict the output and explain each value:
x = 1
def outer():
x = 2
def inner():
return x * 10
return inner() + x
print(outer(), x)
22 1. inner is defined inside outer, so it reads outer's local x = 2 (the nearest enclosing scope) and returns 20. outer returns 20 + 2 = 22. The global x is still 1.
2Refactor this program so it uses no global variables except constants, then explain how it is easier to test.
marks = [70, 85, 92]
best = 0
def find_best():
global best
for m in marks:
if m > best:
best = m
find_best()
print(best)
def find_best(marks):
best = marks[0]
for m in marks:
if m > best:
best = m
return best
print(find_best([70, 85, 92]))
It prints 92. find_best now takes its data as a parameter and returns its result, so you can test it with any list (all negative, one element...) without setting up globals first. It also fixes the start-at-0 bug from Highest, Lowest and Linear Search.
3A loop variable in Python keeps its last value after the loop ends: after for i in range(3): pass, i is 2. Is i local or global if this loop is written at the top level of a file? Inside a function?
At the top level, i is global (it is assigned outside any function). Inside a function, i is local to that function. Loops do not make their own scope in Python.
Check your understandingQuiz
1. Where can a local variable be used?
2. What does this print? x = 1, def f(): x = 5, f(), print(x)
3. Which error do you get from count = 0 and def inc(): count += 1 when inc() is called?
4. Which is usually the best way for a function to give a result to the rest of the program?
5. Which name follows the convention for a global constant?
6. A function can read a global variable without the global keyword. When does it need global?
For parents and teachersBig idea: A3.2 asks for subprograms with appropriate variable scope (e.g., local, global). "Appropriate" means: keep data local, pass it through parameters and return values, and limit globals mostly to constants. A4.2 (professional conventions) appears as CAPITALS for constants; A4.1 as fixing NameError and UnboundLocalError.
How to help: The sticky-note activity is a very effective way to see lifetimes. Ask your teen, "Where does this variable live? When does it disappear?" for each variable in a short program.
Common difficulties:
- Expecting a variable created in a function to exist after the call (NameError).
- Using
global as a quick fix for every scope error. It hides the real problem: the value should have been returned. - Not realizing that assignment anywhere in a function makes the name local for the whole function.
- Confusing "changing a global list's contents" (allowed without
global) with "assigning a new value to the name" (needs global).