Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Exploring the Enclosing Scope

00:00 The enclosing scope, also called the non-local scope, is a scope that exists for inner or nested functions. An inner function is any function defined inside of another function.

00:11 That outer function is then known as the enclosing function. In the enclosing scope, inner functions have access to the local variables of their enclosing functions.

00:21 The scope is created when the outer function is called. At that point, it’s still the local scope of the outer function. Then within the inner function, it’s considered the enclosing, or non-local scope, because from the point of view of the inner function, its names are neither local nor global.

00:39 Now, a unique property of this scope is that it persists between calls of the nested function. This creates what’s known as a closure and enables closure functions, but more on that in a future lesson.

00:50 By default, members of the enclosing scope are read-only, meaning inner functions can’t modify them. However, with the nonlocal statement, you can bring enclosing variables down into the local scope of the inner function.

01:05 This allows the inner function to modify variables from the enclosing scope. However, the nonlocal statement can’t be used outside of the context of a nested function because nonlocal itself is a concept specific to the context of nested functions.

01:22 If you need a quick refresher on nested functions or how they work, check out this course, Python Inner Functions: What Are They Good For? Otherwise, let’s meet up in the REPL.

01:33 Once again, you’ll start by defining a function with a nested function inside, def outer_func(). Create a variable var and set it to 100.

01:44 Start defining the function, inner_func(), def inner_func(). Right now, while var is in the local scope of outer_func(), it is also considered to be in the enclosing scope of inner_func().

01:57 This means from within inner_func(), you can read its value. Print an f-string: f"Printing var from inner_func:

02:07 and the interpolated value of var. inner_func() is done. Now back at the level of outer_func(), call inner_func()

02:16 and add one more line of code. Print the f-string: f"Printing var from outer_func: , the interpolated value of var.

02:28 Now run outer_func() and see what prints. First you see Printing var from inner_func: 100, then Printing var from outer_func: 100.

02:39 You were able to access var from both scopes, and if you tried to call inner_func() from the top level, you of course get a NameError, 'inner_func()'is not defined.

02:50 This is natural because inner_func() only exists within the local scope of outer_func(). Okay, so what if we tweak this example a bit?

02:59 Take the original code and add two new lines.

03:05 Add a second line to the inner_func() function. A call to print() with the f-string: f"Printing another_var from inner_func: and then the interpolated value of the variable another_var. And now back in outer_func(), after you call inner_func(), in the next line, define the variable another_var, and set it to 200.

03:28 another_var = 200.

03:32 Try running this newly defined outer_func() function.

03:37 You get a very interesting NameError, cannot access free variable 'another_var' where it is not associated with a value in enclosing scope.

03:45 What does this mean? When you run outer_func(), its code executes in order. At the point where inner_func() runs, it tries to access another_var, which is yet to be defined, thus a NameError.

04:00 Now for nonlocal. You’ll define a function within a function, and use the nonlocal statement to modify a variable from its enclosing scope. def func().

04:10 Create var, set it to 100, def nested(), and here’s where the nonlocal keyword takes effect. nonlocal var.

04:20 This statement allows code in nested() to modify var, despite it being in a lower level of scope. To try this out, set var += 100, incrementing its value by a hundred. Back outside the nested() function, call nested().

04:36 And finally, print(var) and run func(), the outer function. And the result of the last line of code printing var is 200.

04:45 Because you used the nonlocal statement to bring var into the local scope of the nested function, you were able to modify it with in-place addition.

04:53 Then when you printed var after running nested(), the modified value of 200 was displayed, not the original value of 100.

05:01 And that’s the enclosing scope. Next up, let’s zoom out, way out, all the way to the global scope.

Become a Member to join the conversation.