Python Scope
Scope decides where a name can be seen. A variable created inside a function exists only inside that function, while a variable created at the top of a file can be read everywhere. Understanding scope explains several confusing errors.
- Local and global variables
- The LEGB lookup rule
- When to use global and nonlocal
- Closures that remember values
Local scope
A variable assigned inside a function is local: it is created when the function runs and disappears when it returns.
def make_report(): title = "Daily report" # local print(title) make_report()print(title)Daily report
Traceback (most recent call last):
File "main.py", line 6, in <module>
print(title)
^^^^^
NameError: name 'title' is not defined. Did you mean: 'tuple'?Global scope
A variable assigned at the top level of a file is global. Functions can read it.
BASE_URL = "https://sqatools.in" def page_url(path): return BASE_URL + path # reading a global is fine print(page_url("/python-tutorials/"))https://sqatools.in/python-tutorials/
Same name, different variables
Assigning inside a function creates a new local variable, even if a global has the same name. The global is untouched.
count = 10 def reset(): count = 0 # a new local count print("inside:", count) reset()print("outside:", count)inside: 0 outside: 10
The LEGB rule
When Python looks up a name, it searches four scopes in order and uses the first match:
| Order | Scope | Example |
|---|---|---|
| L | Local: the current function | variables assigned in the function |
| E | Enclosing: outer functions | variables of a function that contains this one |
| G | Global: the module | top-level variables and functions |
| B | Built-in | print, len, max |
x = "global" def outer(): x = "enclosing" def inner(): print(x) # not local, found in the enclosing function inner() outer()print(len("built-in lookup"))enclosing 15
The global keyword
To assign to a global variable inside a function, declare it with global:
counter = 0 def increment(): global counter counter += 1 increment()increment()print(counter)2
Functions that change globals are hard to test and reason about. Prefer passing values in and returning results: counter = increment(counter).
UnboundLocalError
If a function assigns to a name anywhere, that name is local for the whole function. Reading it before the assignment fails:
total = 100 def add_tax(): total = total * 1.18 # total is local here, but has no value yet return total add_tax()Traceback (most recent call last):
File "main.py", line 7, in <module>
add_tax()
~~~~~~~^^
File "main.py", line 4, in add_tax
total = total * 1.18 # total is local here, but has no value yet
^^^^^
UnboundLocalError: cannot access local variable 'total' where it is not associated with a valueThe fix is to pass the value in: def add_tax(total): return total * 1.18.
nonlocal and closures
nonlocal lets an inner function assign to a variable of its enclosing function. The inner function keeps that variable alive even after the outer function has returned. This is called a closure.
def make_counter(): count = 0 def next_value(): nonlocal count count += 1 return count return next_value ticket = make_counter()print(ticket(), ticket(), ticket()) other = make_counter() # a separate countprint(other())1 2 3 1
Closures are useful for creating customised functions:
def make_multiplier(factor): def multiply(x): return x * factor return multiply double = make_multiplier(2)triple = make_multiplier(3)print(double(5), triple(5))10 15
Check your understanding
Predict the output
x = 1def f(): x = 2 def g(): nonlocal x x = 3 g() return xprint(f(), x)3 1
nonlocal makes g change the x of f, so f returns 3. The global x was never touched and is still 1.
Quick quiz
1. In what order does Python look up a name?
LEGB: local, enclosing, global, built-in.
2. What is needed to change a module-level variable inside a function?
Without global, assignment creates a new local variable.
3. Why does UnboundLocalError happen?
Any assignment in a function makes that name local for the whole function.
Exercise: running average
Write make_averager() that returns a function. Each call adds a number and returns the average so far.
10, then 20, then 60
10.0 15.0 30.0
Hint 1
Keep total and count in the outer function and use nonlocal.
def make_averager(): total = 0 count = 0 def add(value): nonlocal total, count total += value count += 1 return total / count return add avg = make_averager()print(avg(10), avg(20), avg(60))10.0 15.0 30.0
The inner function updates total and count of the outer function on every call. Because the closure keeps them alive, each new value is added to the earlier ones.
Program Practice
39 Python Function Programs
Every program has a step-by-step explanation, colour-coded code and its real output.
Python scope FAQ
What is the difference between local and global variables in Python?
A local variable is created inside a function and exists only while it runs. A global variable is created at the top level of a module and can be read anywhere in it.
When should I use the global keyword?
Rarely. Use it only when a function really must rebind a module-level variable. Passing values in and returning results is usually clearer.
What does nonlocal do in Python?
It lets a nested function assign to a variable of the enclosing function instead of creating a new local one.