Nested Functions and Enclosing Scope
Learn about the enclosing scope, which allows nested functions to access variables defined in their outer (enclosing) function.
We've already learnt that functions can access variables defined in their own local scope, as well as in the global scope.
#### global scope ####
...
def my_function():
#### local scope ####
...
When we are dealing with nested functions, there's an additional type of scope: the so-called enclosing scope.
The enclosing scope refers to the region where the outer function's variables are accessible by the inner (nested) function.
Even though the inner function has its own scope, it can still access variables from the outer function.
From the perspective of the inner function, there are 3 different scopes:
#### global scope ####
...
def outer():
#### enclosing scope ####
...
def inner():
#### local scope ####
...
That means the inner function can access variables defined in the global scope...
#### global scope ####
global_var = 'global'
def outer():
#### enclosing scope ####
def inner():
#### local scope ####
print(global_var)
inner()
outer()
And variables defined in the enclosing scope...
#### global scope ####
def outer():
#### enclosing scope ####
enclosing_var = 'enclosing'
def inner():
#### local scope ####
print(enclosing_var)
inner()
outer()
And variables defined in its own local scope...
#### global scope ####
def outer():
#### enclosing scope ####
def inner():
local_var = 'local'
#### local scope ####
print(local_var)
inner()
outer()
In Python, the way variables are looked up follows a specific order, or hierarchy.
This hierarchy determines where Python starts looking for variable names.
The order goes from inside to outside:
Local Scope > Enclosing Scope > Global Scope
This order is important when multiple variables with the same name exist in different scopes.
For example, in this case, the local version of x
takes precedence over the others:
x = 'global'
def outer():
x = 'enclosing'
def inner():
x = 'local'
print(x)
inner()
outer()
If there's no local version of x
, the enclosing version takes precedence over the global one:
x = 'global'
def outer():
x = 'enclosing'
def inner():
print(x)
inner()
outer()
What will be the output?
x = 10
def outer():
y = 20
def inner():
z = 30
print(x, y, z)
inner()
outer()
What will be the output?
x = 10
def outer():
x = 20
def inner():
x = 30
print(x)
inner()
outer()
What will be the output?
x = 10
def outer():
x = 20
def inner():
x = 30
print(x)
inner()
outer()
What will be the output?
x = 10
def outer():
x = 20
def inner():
x = 30
inner()
print(x)
outer()
What will be the output?
x = 10
def outer():
x = 20
def inner():
print(x)
inner()
outer()