Variable Scope in Python
Scope is the part of a program where a variable name can be used. A variable created inside a function is local to it, and one created at the top level of a file is global. A function can read a global, but assigning to it needs the global keyword.
Key facts
- A variable assigned inside a function is local to it and normally disappears when the function returns.
- A function can read a global variable without any keyword.
- Assigning to a name anywhere in a function makes it local for the whole function, so reading it before the assignment raises
UnboundLocalError. global countlets a function assign to the globalcount, andnonlocaldoes the same for a variable of an enclosing function.- Python looks up a name in the local, enclosing, global and built-in scopes, in that order. This order is called the LEGB rule.
What is scope in Python?
Scope is the part of a program where a variable name can be used. Each function call gets its own set of names, so a variable created inside a function can only be used inside it.
def make_greeting():
message = "Hello!"
print(message)
make_greeting()
print(message)Hello!
Traceback (most recent call last):
File "main.py", line 6, in <module>
print(message)
^^^^^^^
NameError: name 'message' is not definedInside the function, message works. Outside, the name can't be seen, because it belongs to the function's own set of names, which Python calls a namespace.
What is the difference between local and global variables?
A local variable lives inside one function, and a global variable lives outside every function, at the file's top level. Every function in the file can read a global variable, with no keyword needed.
tax_rate = 0.2
def price_with_tax(price):
return price + price * tax_rate
print(price_with_tax(100))120.0
Parameters are local variables too. In price_with_tax(), price is local, and tax_rate is read from the global scope because the function never assigns to it.
| Question | Local variable | Global variable |
|---|---|---|
| Where is it created? | Inside a function, by an assignment or as a parameter | At the top level of the file |
| Where can it be used? | Only inside that function | Anywhere in the file, including inside functions |
| How long does it last? | Until the function returns (the nonlocal section shows an exception) | Until the program ends |
| Assigning to it inside a function | Works as usual | Needs global, or Python creates a local variable instead |
Why doesn't an assignment inside a function change a global variable?
Assigning to a name inside a function creates a local variable, even when a global variable has the same name. The global keeps its value, and the local one disappears when the function returns.
count = 0
def reset():
count = 10
print("inside:", count)
reset()
print("outside:", count)inside: 10 outside: 0
The two count variables share a name and nothing else. The rule protects you, because a function can't overwrite a global by accident when it reuses a common name such as total or i.
How do I change a global variable inside a function?
Put global and the name at the top of the function, as in global count. Assignments to that name then change the global variable instead of creating a local one.
count = 0
def increment():
global count
count += 1
increment()
increment()
print(count)2
Even so, most Python code avoids global. A function that changes globals is harder to test and reuse, because its result depends on values outside it. The usual alternative is to pass the value in and return the new one.
def increment(n):
return n + 1
count = 0
count = increment(count)
count = increment(count)
print(count)2
This version has no hidden link to the outside, so each call shows which value goes in and where the result goes.
Why do I get UnboundLocalError in Python?
Python raises UnboundLocalError when a function reads a local variable before giving it a value. A name is local if the function assigns to it anywhere in its body, because Python decides which names are local before the function runs.
count = 0
def increment():
count = count + 1
increment()
print(count)Traceback (most recent call last):
File "main.py", line 6, in <module>
increment()
~~~~~~~~~^^
File "main.py", line 4, in increment
count = count + 1
^^^^^
UnboundLocalError: cannot access local variable 'count' where it is not associated with a valueThe assignment makes count local for the whole function, so the count + 1 on the right reads a local variable that has no value yet. The traceback shows both steps, the call on line 6 and the failing line inside increment(). Add global count at the top of the function and the program prints 1.
Can a function change a global list without the global keyword?
Yes. Calling a method such as append() changes the list itself, and that isn't an assignment to the name.
items = []
def add(item):
items.append(item)
add("pen")
add("book")
print(items)['pen', 'book']
The function reads the global name items, finds the list, and changes that list in place. You need global only to make the name point to a different object, as in items = [].
Watch out for items += ["pen"] inside the function. On a list, += works like extend(), but it also assigns the result back to the name. That makes items local, so the line raises UnboundLocalError before the list changes.
What is the LEGB rule in Python?
LEGB stands for local, enclosing, global and built-in, the four scopes Python searches in that order to find a name. A name the function assigns to is local, unless a global or nonlocal line says otherwise. Python looks up any other name outward and raises NameError if no scope has it.
name = "global"
def outer():
name = "enclosing"
def inner():
print(name)
print(len(name))
inner()
outer()enclosing 9
A function defined inside another function is a nested function, and the outer one is its enclosing function. inner() has no local variable called name, so Python looks in outer() and finds "enclosing" before it reaches the global one.
len isn't in any of the first three scopes, so Python finds it in the built-in scope.
| Letter | Scope | What it holds |
|---|---|---|
| L | Local | Names assigned inside the current function, including its parameters |
| E | Enclosing | Local names of any function the current one is nested inside |
| G | Global | Names assigned at the top level of the file |
| B | Built-in | Names Python provides everywhere, such as print, len and ValueError |
What does nonlocal do in Python?
nonlocal lets a nested function assign to a variable of its enclosing function. It works like global for the enclosing scope, and without it the assignment would create a new local variable.
def make_counter():
count = 0
def increment():
nonlocal count
count += 1
return count
return increment
counter = make_counter()
print(counter())
print(counter())1 2
make_counter() returns the inner function without calling it, so counter now refers to increment(), and each counter() call runs it.
Normally count would disappear when make_counter() finishes, but increment() keeps it alive. A function that remembers variables from its enclosing scope like this is called a closure.
A nonlocal line at the top level of a file is a SyntaxError, because there is no enclosing function to point to.
Common mistakes with variable scope in Python
Four mistakes cause most scope bugs, and only the third one runs without an error.
- UnboundLocalError: cannot access local variable 'count' where it is not associated with a value. The function reads a name before assigning to it, and the assignment makes that name local. Add
global count, or pass the value in and return it. - NameError: name 'message' is not defined. Code outside a function used a variable created inside it. Return the value and store it where the function is called.
- Expecting an assignment to change a global. Without
global, the assignment creates a local variable and the global keeps its old value, with no error at all. - TypeError: 'list' object is not callable. A variable named
listhides the built-inlist(), because the global scope is searched before the built-in one, solist("abc")tries to call a list. Rename the variable, for example toitems.
Run the program to see the last message. Then change list on line 1 to items, leave line 2 as it is, and the program prints ['a', 'b', 'c'].
list = [1, 2]
print(list("abc"))Traceback (most recent call last):
File "main.py", line 2, in <module>
print(list("abc"))
~~~~^^^^^^^
TypeError: 'list' object is not callableExercise
Add one line to add_point() so it changes the global score, and the program prints 3. The starter stops with an UnboundLocalError on the first call.
score = 0
def add_point():
score += 1
add_point()
add_point()
add_point()
print(score)
3
Show the solution
score = 0
def add_point():
global score
score += 1
add_point()
add_point()
add_point()
print(score)
Quiz
This quiz has 5 questions. Pick an answer to see why it is right or wrong.
-
1What does this program print?
x = 5 def f(): x = 10 f() print(x)The assignment inside f() creates a local x, so the global x keeps its value of 5. A global x line in the function would make the assignment change the global.
-
2What does this program print?
def f(): y = 1 f() print(y)y is local to f(), so code outside f() can't see it, and print(y) raises NameError. Returning y and storing the result would make the value available outside.
-
3Which keyword lets a function assign to a variable created at the top level of the file?
global makes assignments inside the function change the top-level variable. nonlocal does the same for a variable of an enclosing function, and Python has no local keyword.
-
4What does this program print?
greeting = "Hi" def say(): print(greeting) say()A function can read a global variable without any keyword, so say() prints Hi. The global keyword is needed only to assign to it.
-
5In what order does Python search scopes to find a name?
Python searches from the innermost scope outward, which is the LEGB rule. It uses the first scope that has the name.























