Debugging the outer() Function
00:00 In this lesson, you’ll use the Thonny debugger to step through this piece of code that you quickly refactored in the previous lesson, and then you’ll hopefully get a good idea of what’s going on in terms of different scopes and closures in this example code snippet here.
So to get started debugging, I’m going to click on the Debug current script button in the top of the Thonny menu bar. It’s a little bug symbol. And when you click this, then it starts the debugger, and you can already see that it nicely highlights the first thing that it’s going to execute inside of the script when you run it, which is going to be the function definition of
So these variables, for example
message here or also the
inner() function, they haven’t been defined yet because you just create the
outer() function at first, and only when you call the
outer() function, all of these variables in here are going to get defined.
And this is going to happen in the next line of code. On line 11, you’re actually going run the
outer() function. You’re going to call it. So in this case, what happens is that Python needs to understand what does this
outer() refer to?
01:48 So I can see in here how Thonny’s debugger nicely shows what’s going on here visually. You can see that it even opens up a new window that represents the new scope that you’re working with in here.
And if you have some understanding of scopes, then you know that this scope has access to the global variables, but for example, any variable that you define in here is not going to be accessible in the global scope. And this local scope during the function execution now actually starts to define also the
And now next you’re going to define a variable
message. And first Python needs to understand what is this
'hello', and it figures out it’s a string and then assigns that string to the variable
message. And you can see that one pop up in your local variables here as well.
So Python understands what’s going on, and because this is a new function call, it opens up yet another scope for the
inner() function. So this is a new local scope that relates to the
Because you have access to the higher-up scope—in this case, it’s called the nonlocal scope to the
inner() function because it’s, you’re talking about a nested function that lives inside of another function—so this nested function has access to the variables that were defined in the function that contains the
inner() function. So in our case, this is the
So this is why you can see that the
inner() function comes with a local scope that says
message 'hello'. So the correct term is to call this variable a nonlocal variable because it isn’t defined inside of the local scope of the
inner() function, but in the higher-up scope of the
outer() function. Now, if I keep stepping, you’re going to see that Python understands that this is a call to the
print() function. It evaluates the variable
message in here, understands it points to the string
'hello', and then knows what to do with it, which is print it to the console.
So you can see it come up out here in your script. In the output, you can see
hello printed to the console. And this
None that you can see there is just the return value of the
print() function, which is
The next step is going to be closing the scope because the function execution is over, and it returns something, and because you don’t have an explicit
return value in the function definition of
inner(), Python returns the default of
So this is also what Thonny is showing you here. And this ends the local scope of this specific call to the
inner() function. Every function call opens up its own scope, even if you call the same function object multiple times.
So if you keep going now, you’ll see that you’re back inside of the scope of the
outer() function, and here the
message variable is going to be redefined to something else. It’s going to point now to the string
You can also see that change down here in the local variables. And you’re back to another call to the
inner() function. That is going go down pretty similarly to what happened just before. So let’s step through it.
And you can see it come up here in the console as well. You have another return value of
None for the
print() function call, and then another return value of
None for the call to the
All right, and then your
outer() function is about to return, and this function doesn’t return
None, but instead it returns the function object
inner, figures out what that is—that is a function object in the local of the outer function called
inner()—and that gets returned. You can see it here is the return value of the function call that you started with, and it gets assigned to
inner_returned, and now it lives inside of here.
And I’m going to stop this lesson and give you a chance to try it out yourself and see whether what happens is what you expect to happen. Once you’re done, move to the next video, and you’re going to see what happens when we step through this final call to
Become a Member to join the conversation.