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

Accessing Variables in the Enclosing Scope

00:00 In this lesson, you look at another example. You’ll note many similarities between this example and one from the previous lessons. And that’s a good thing because you can use it to review the key concepts about closures.

00:11 However, there will be some important differences as well, and I’ll guide you through them. You’re still going to use the print() built-in function, but this time you would like to keep track of how many times you call it within a program.

00:26 As you’ve done previously, you’ll create another function. Let’s call this print_with_counter().

00:33 Instead of a list to store arguments, all you need now is a variable counter, which will count how many times we’ve called the function, so we’ll start with zero.

00:43 You still need to have your inner function and this will be, we’ll put a placeholder for now. This is the function that will replace your print(), but this one will keep track of how many times it’s been called.

00:56 In the previous example, you put a single parameter here. However, you can make this more general by using *args and **kwargs. This allows this function to accept any number of positional arguments and any number of keyword arguments.

01:13 And in there, it needs to call print() and you can pass args and kwargs back into print(). So the inner function will print things out.

01:23 However, it needs to do something else as well. It needs to keep track of the counter, so you will ideally like to take your counter and increment it by one.

01:33 You’ll see that there’s a problem with this line, but we’ll get to this soon.

01:38 Next, you need to return the inner function from within the outer function called print_with_counter().

01:46 And in the main code, you can now create print_ your version of print(). And print_ be equal to whatever print_with_counter() returns, and print_with_counter() returns the inner function.

02:01 So now you have a function called print_. You can call it a few times, Real Python as the first argument, and the second time, as we’ve done earlier, you can call it with I love Python or anything you want really.

02:17 So let’s try to run this code.

02:21 And this is where we get the problem. Python raises an error. We have an UnboundLocalError. The issue is with the variable counter within the function inner().

02:35 In the previous example, we did not have this problem and we said that the function inner() has access to any variables defined within an outer function.

02:45 However, this line, let’s write it in full to make it clear. This line is equivalent to saying counter is equal to counter plus one, and therefore the inner() function is creating its own local variable called counter.

02:59 It’s no longer using the counter used in the outer function. And therefore this line causes a problem because you’re defining a new local variable counter, but you’re also trying to use it at the same time.

03:11 That’s where we get the UnboundLocalError. You would like to let your program know that this counter should be the same counter that you defined in the outer function, in the enclosing scope.

03:24 And the way to do that is to use the nonlocal keyword. The enclosing scope is also called the non-local scope and the nonlocal keyword let’s Python know that you want to use the counter that’s defined in the non-local scope or the enclosing scope.

03:42 And when you run this code, now you don’t get any errors because counter is no longer a local variable within inner.

03:51 Now there’s still the issue that the variable counter is not accessible in the global scope. It’s accessible in the enclosing scope and in the local scope of inner, but not in the global scope.

04:03 Let’s look at another alternative, how you can make it available in the global scope. Within print_with_counter(), the outer function, you can define another inner function.

04:14 You can call this get_counter().

04:18 And this function returns the variable counter.

04:22 You don’t need to use the nonlocal keyword in this case, because you’re not making changes to counter, you’re simply accessing it.

04:28 Accessing the variable from the enclosing scope is perfectly fine. It’s when you want to make changes to it, such as reassigning a value to it that you have to use the nonlocal keyword.

04:39 However, this still creates a new local name, the name of the function get_counter(), which is still local to the outer function print_with_counter(). However, the outer function is returning inner, so you can attach a new data attribute to inner.

04:55 You can call it anything you want, but let’s still call it get_counter. And this attribute is equal to the inner function get_counter.

05:04 And since inner is returned to the global scope, you’ll be able to access get_counter using the attribute inner.get_counter.

05:15 Let’s try this out. In the global scope, inner does not exist, but print_ is the name that refers to this inner function. So let’s use the standard print() this time to print print_. And get_counter is a function, so you need to add the parentheses to call it.

05:36 And when you run the script, you see that the two calls, the print_ print the string, but the final print shows you that the print_ function was called twice.

05:49 And you can test this further by calling print_ again. Since you’re using *args and **kwargs, you can put in several arguments and even keyword values such as the separator.

06:04 And after you call print_ again, you can once again display the output from print_ .get_counter.

06:17 And this time after printing 3, 4, 5 get_counter returns the value 3 since print_ has now been called three times.

Become a Member to join the conversation.