Scope
A variable's scope is the part of the program where its name can be used. Up to lesson 15, every variable lived in one big space. Functions change that: each call gets its own space for its variables, and that space is gone when the call ends.
1def light_street():2 lamps = 33 print("Lit", lamps, "lamps")4 5light_street()6print(lamps)
Lit 3 lamps
Traceback (most recent call last):
File "main.py", line 6, in <module>
print(lamps)
NameError: name 'lamps' is not definedLocal variables
lamps is created inside the function, so it is a local variable: it belongs to that call. Outside the function the name does not exist, and the last line stops with a NameError. Parameters are local variables too.
Tip: Press Step on the example above. When the call starts, lamps appears in the function's own group of variables. When the call ends, the group is gone, and lamps with it.
To get a value out of a function, don't reach for its local variables. Use return:
1def light_street():2 lamps = 33 return lamps4 5count = light_street()6print(count)
3
Each call starts fresh. A local variable does not remember its value from the call before.
Global variables
A variable made outside every function, at the top level of the program, is a global variable. Functions can read it:
1price = 42 3def cost(count):4 return count * price5 6print(cost(3))7price = 58print(cost(3))
12 15
The function looks up price each time it runs, so it sees the latest value.
Two variables, one name
Assigning to a name inside a function always makes a new local variable, even when a global one has the same name. The global one is not touched.
What does the last line print?
1lamps = 102 3def night_shift():4 lamps = 25 print("inside:", lamps)6 7night_shift()8print("outside:", lamps)
lamps = 2 inside the function makes a second, local lamps. The global lamps is still 10.
Changing a global: global
So what happens when a function tries to add to a global counter? Python decides before the function runs: since count is assigned somewhere in the function, it is local everywhere in the function. Then count += 1 tries to read the local count before it has a value, and stops with an UnboundLocalError:
1count = 02 3def add_lamp():4 count += 15 6add_lamp()
Traceback (most recent call last):
File "main.py", line 6, in <module>
add_lamp()
File "main.py", line 4, in add_lamp
count += 1
UnboundLocalError: cannot access local variable 'count' where it is not associated with a valueTo change the global variable, say so with global at the top of the function:
1count = 02 3def add_lamp():4 global count5 count += 16 7add_lamp()8add_lamp()9print(count)
2
global works, but use it sparingly. A function that changes globals is harder to follow, because any call anywhere could change the value. Passing values in and returning results is usually clearer.
Nested functions and nonlocal
A function can be defined inside another function. The inner one is local to the outer one, and it can read the outer function's variables. To change one of them, use nonlocal: it means "the variable from the function around me".
1def light_route(streets):2 lit = 03 def light_one(street):4 nonlocal lit5 lit += 16 print(f"{lit}. {street}")7 for street in streets:8 light_one(street)9 return lit10 11print("Total:", light_route(["Mill Road", "Market"]))
1. Mill Road 2. Market Total: 2
Without nonlocal, lit += 1 would make lit local to light_one and fail just like the global example. Press Step: while light_one runs, you can see its variables and light_route's side by side.
Where Python looks: LEGB
When Python meets a name, it looks for it in four places, in this order, and uses the first one it finds:
| Letter | Scope | What lives there |
|---|---|---|
| L | Local | the current function's variables and parameters |
| E | Enclosing | the variables of the functions around it |
| G | Global | variables made at the top level of the program |
| B | Built-in | names Python always has: print, len, sum, ... |
1name = "global"2 3def outer():4 name = "enclosing"5 def inner():6 print(name)7 print(len(name))8 inner()9 10outer()
enclosing 9
inner has no name of its own (L), so Python finds the one in outer (E) before the global one. len is in none of the first three, so it comes from the built-ins (B). If a name is in none of the four, you get a NameError.
Don't hide built-in names
Built-ins come last in the search. So a variable called list, sum or max hides the built-in function with that name, and the next call to it breaks:
1list = ["iron", "gold"]2print(list)3letters = list("ore")
['iron', 'gold']
Traceback (most recent call last):
File "main.py", line 3, in <module>
letters = list("ore")
TypeError: 'list' object is not callablelist now means your list, and a list cannot be called. Pick another name, like ores or items. Watch out for list, dict, str, sum, max, min, input and type.
Practice
Write the code, then press Check. A hint costs nothing; the answer is there when you need it. Each starting program has a scope problem: run it first and read the error.
Get it out
✓The last line fails with a NameError. Change the program so the function hands its total back and the last line prints it.
12
1def add_up(loads):2 total = sum(loads)3 4add_up([3, 4, 5])5print(total)
Count the calls
✓ring() should add 1 to the global rings each time it is called. Make it work.
3
1rings = 02 3def ring():4 rings += 15 6ring()7ring()8ring()9print(rings)
A hidden built-in
✓The variable sum hides the built-in sum(), so the last line fails. Rename the variable so both lines print.
10 3
1loads = [3, 5, 2]2sum = 03for ore in loads:4 sum += ore5print(sum)6print(sum([1, 2]))
What you learned
- Variables made in a function are local: they exist only during that call. Use
returnto get a value out. - Global variables, made at the top level, can be read inside functions.
- Assigning to a name in a function makes it local, even if a global has the same name; reading it before then is an
UnboundLocalError. global namelets a function change a global;nonlocal namelets a nested function change the outer function's variable.- Python looks up names in the order Local, Enclosing, Global, Built-in. Don't name variables
list,sumormax.