Function Scope

Learn about variable scope in Python functions, including local, global, and nonlocal scopes.

Ali Berro

By Ali Berro

5 min read Section 4
From: Python Fundamentals: From Zero to Hero

Function Scope

From other languages we know that a function creates a scope, where the variables inside a function are not accessed from the outside world.

Given the following code, when we try to access the variable x, Python tries to search for it in the current scope. When it fails to find it, it searches in the upper scope until it goes to the global scope, finds it then uses it:

scope-search.py
x = 1
def test():
y = 2
print(x)
test() # 1

Nested Functions

This also works for nested functions:

nested-functions.py
x = 1
def f1():
y = 2
def f2():
print(x)
f2()
f1() # 1

Due to this scope search behavior, we could shadow a global variable by introducing a variable with the same name in the local scope.

In this example, when we search for x in f2(), Python first looks in the local scope of f2(). Not finding it there, it looks in the enclosing scope (the local scope of f1()), finds x = 2, and uses that value:

shadowing.py
x = 1
def f1():
x = 2
def f2():
print(x)
f2()
f1() # 2

The global Keyword

How can we change the value of a global variable if when we write x = 3, it creates a new variable in the local scope?

For that we have to use the global keyword:

global-keyword.py
x = 1
def f1():
global x
x = 2
def f2():
print(x)
f2()
f1() # 2
print(x) # 2

global x tells Python to use the global variable x instead of creating a new local variable.

The nonlocal Keyword

What if we had a variable in the global and local scope with the same name, and we need the inner nested function to change the local value?

nonlocal-problem.py
x = 1
def f1():
x = 2
def f2():
# Update the local variable's value
x = 3
print(x)
f2()
f1() # 3

To tell Python that this variable is not really a local variable and our intent is to reference an earlier created variable, we use the nonlocal keyword:

nonlocal-keyword.py
x = 1
def f1():
x = 2
def f2():
nonlocal x
x = 3
print(x)
f2()
f1() # 3

nonlocal x tells Python to use the local variable x instead of creating a new local variable.

Exercises

Exercise 1: Scope Search

What will be printed by the following code? Explain the scope search process.

x = 10
def outer():
y = 20
def inner():
print(x)
print(y)
inner()
outer()
Answer:
10
20

Python searches for x in inner’s local scope, then outer’s scope, then finds it in global scope. For y, it finds it in outer’s (enclosing) scope.

Exercise 2: Shadowing

What will be printed by the following code?

x = 1
def f1():
x = 2
def f2():
print(x)
f2()
print(x)
f1()
print(x)
Answer:
2
2
1

The local x in f1() shadows the global x. f2() accesses the enclosing scope’s x (which is 2). The global x remains 1.

Exercise 3: Global Keyword

Write code that modifies a global variable counter inside a function. Start with counter = 0, read the number of times to increment, then increment it that many times in a function using the global keyword.

Global Keyword

Checks: 0 times
Answer:
counter = 0
def increment():
global counter
counter += 1
n = int(input())
for i in range(n):
increment()
print(counter)

Exercise 4: Nonlocal Keyword

Write a nested function where the inner function modifies a variable from the enclosing scope using nonlocal. The outer function should have count = 0, and the inner function should increment it.

Answer:
def outer():
count = 0
def inner():
nonlocal count
count += 1
print(count)
inner()
inner()
return count
result = outer() # Prints 1, then 2
print(result) # 2

Exercise 5: Scope Error

Why does the following code raise an error? How would you fix it?

x = 5
def test():
print(x)
x = 10
test()
Answer:

It raises UnboundLocalError because Python sees x = 10 and assumes x is local, but tries to print it before it’s assigned. Fix by using global:

x = 5
def test():
global x
print(x) # 5
x = 10
test()
print(x) # 10

Course Progress

Section 35 of 61

Back to Course