Scope of a Variable
The scope of a variable is the part of the program where its name means something. A name made inside a function lives only there and disappears when the function ends; a name made outside every function is visible throughout. Getting this right is what stops two functions quietly overwriting each other's work.
1Local scope: made inside, gone outside
def show():
message = 'I live inside show()'
print(message)
show()
print(message)I live inside show()
Traceback (most recent call last):
File "local_scope.py", line 6, in <module>
print(message)
^^^^^^^
NameError: name 'message' is not definedThe function printed it happily. One line later the same name does not exist. message is a local variable — it was created when the function ran, and destroyed when it finished.
i without any of them interfering with the others. Each call gets its own private set of names.def one():
x = 'in one'
print(x)
def two():
x = 'in two'
print(x)
one()
two()in one in two
Two variables, both called x, with no relationship to each other whatsoever. And a parameter is local too — it is just a local name that the call fills in for you:
def f(n):
n = n * 2
return n
value = 7
print(f(value))
print(value)14 7
2Global scope: made outside, visible inside
A name created outside every function is global, and a function can read it without being given it:
school = 'LambdaLab Public School'
def header():
print(school) # reading a global — allowed
header()LambdaLab Public School
Python looks for school among the function's own local names first, does not find it, and looks outside. That is the whole rule: local first, then global.
3Assigning inside makes a new local
Here is the behaviour that surprises everyone, and it is worth staring at until it stops being surprising:
count = 10
def change():
count = 99 # this makes a NEW local variable
print('inside :', count)
change()
print('outside:', count)inside : 99 outside: 10
count — it made its own, used it, and threw it away. The global was never touched, which is why it is still 10.Python decides this when it compiles the function, not while it runs — so a name assigned anywhere in the body is local everywhere in the body, including on lines above the assignment:
total = 5
def broken():
print(total) # Python already knows total is local here
total = 6 # …because of this line
broken()Traceback (most recent call last):
File "unbound_local.py", line 7, in <module>
broken()
File "unbound_local.py", line 4, in broken
print(total) # Python already knows total is local here
^^^^^
UnboundLocalError: cannot access local variable 'total' where it is not associated with a value“Local variable, not associated with a value” is Python telling you exactly that: it decided total was local because of the assignment below, and then you asked to read it before anything had been put in it.
4global: changing the outside one on purpose
When you really do mean the global, say so:
count = 10
def change():
global count # 'count' means the outside one
count = 99
print('inside :', count)
change()
print('outside:', count)inside : 99 outside: 99
One word, and now both lines print 99. global count tells Python not to make a local — every mention of count in this function refers to the one outside.
return keeps the function self-contained, which is the whole point of writing functions.total = 0
def add(n):
global total
total = total + n
add(5)
add(3)
print(total)Works, and the function is now tangled up with the rest of the program.
def add(total, n):
return total + n
total = 0
total = add(total, 5)
total = add(total, 3)
print(total)Same answer, and add can be read, tested and reused on its own.
5The rules, all together
| Inside a function | What happens |
|---|---|
| Reading a name that is local | Uses the local one. |
| Reading a name that is only global | Uses the global one. No keyword needed. |
| Assigning to a name | Creates a local — even if a global of that name exists. |
| Assigning after declaring it global | Changes the global itself. |
| Reading a name that is assigned later in the body | UnboundLocalError — it is local, and still empty. |
| Changing a list that was passed in | The caller sees the change. The name is local; the list is not. |
6Recap
Created when the function runs, destroyed when it ends. Parameters are local too.
A function looks for a local name first, then a global one. Reading needs no keyword.
count = 99 inside did not touch the count outside. That is the commonest surprise in this chapter.
Use it rarely: a function that changes globals cannot be understood on its own.
- 1
Make a variable inside a function and try to print it after the call.
Hint ·
NameError. The name existed only while the function was running. - 2
Write the
count = 10/count = 99example both with and withoutglobal.Hint · Without: 99 inside, 10 outside. With: 99 in both places. One keyword is the whole difference.
- 3
Read a global at the top of a function and assign to it at the bottom.
Hint ·
UnboundLocalError. Python decided the name was local before it ran a single line. - 4
Rewrite a function that uses
globalso it takes a parameter and returns a value instead.Hint ·
total = add(total, 5). The function stops depending on anything outside itself.
count = 10 outside; a function assigns count = 99 and prints it. What do the two prints show?
Why does reading a global at the top of a function fail if you assign to it lower down?
When do you actually need the global keyword?