Working With Closures
00:00
Now that you’ve learned about inner functions and scope, you’re ready to start working with closures. And let’s start by having a look at an example. You can create a new script called closures.py
, and let’s use the beloved print()
built-in function in this example. However, you would like to keep a record of all the arguments you pass to your function so that every time you call the function, whatever argument you pass is stored somewhere.
00:28
So you can create your own version of print()
, let’s call it print_
with a trailing underscore for now. And to keep it simple, let’s just have one parameter.
00:37
So when you call this function print_
, you’ll only be able to pass one argument.
00:42
Now you want your version of print()
to call the built-in print()
and pass data to it because you still wanted to print things to the screen.
00:50
However, you also want to keep a record of the argument you pass. What you cannot do is create, for example, a list called record
within the function, and then you append to it.
01:02
Why? Because every time you call your function, Python will create a new list, a new empty list, which is local to the function. That’s not what you want because you want a central repository where every time you call your function print_
, the arguments are stored in that common place.
01:21
So an alternative to this would be to define the list record
instead of inside the function, you could define it outside the function. For example, just before you define the function.
01:31
This means it’s in the global scope, and functions in Python have access to variables defined in the global scope. Therefore, you can now append data to your list record
.
01:44
You can confirm that this works by calling your version of print()
, print_
, let’s call it a few times. For example, you can call it with the argument “Real Python”.
01:54
And then you can call it again with some other argument. Let’s say “I love Python”. Because we all love Python here, right? And therefore each time you call the function print_
, it should print whatever its argument is but also keep a record of its arguments.
02:12
And let’s confirm that by using the built-in print()
this time. So the standard print()
, and to print the list record
.
02:22
So in the terminal, I can run the script. I call the script closures
. We don’t have closures yet in the script, but we will soon. And when you run the script, you can see there are three lines of output.
02:35
The first two are the printouts of the string “Real Python” and “I love Python”. That’s because your version of print()
, print_
performs the same action as the built-in print()
.
02:45
However, the final line shows the list record
, and you can see that each time you called your function print_
, the argument was stored in the list record
.
02:56
However, this is not the ideal solution because the list record
is in the global scope, therefore it can be accessed by any part of your program.
03:06 This could lead to issues such as accessing this list when you’re not meant to, perhaps overriding it or adding something to it when you’re not meant to do so.
03:15
Also, if you wanted to perform the same action with another function, for example, other than print()
, then you’d have to create a separate list and give it a separate name.
03:25
So you’ve seen that the list record
cannot be in the function’s local scope. It can be in the global scope, but ideally you don’t want it there.
03:34 Is there an in-between solution? Is there a compromise? Ideally, you’d like to create a scope, a region within your program where variables exist. That includes the function as well as a bit more outside of it.
03:50
You want to create an enclosure around your function that also includes the list record
. And one way of doing that is by creating another function.
04:00 So if we indent all of that,
04:03
and you can call the outer function print_with_memory()
, say,
04:09
the outer function now includes all of those lines within its scope. Therefore the list record
and the inner function print_
are both within the same scope.
04:23
record
and print_
are both names that exist within the same scope, the local scope of the function, print_with_memory()
.
04:32
Therefore, the list record
is not in the global scope this time, however, it’s not in the local scope of print_
either. It’s within the scope of the outer function.
04:43
print_with_memory()
and print_
can access record
.
04:49
So you’ve defined an inner function print_
within an outer function, print_with_memory
. However, this code still doesn’t work.
04:58
If you try running the script again, you see that you get a NameError:
name
print_ is not defined.
05:05
The problem is when you call print_
in the global scope, because the name print_
only exists within the outer function print_with_memory()
, it does not exist in the global scope.
05:18
So there’s still a bit more work to do in order to achieve what you want to have something equivalent to the print()
function, but that also stores all the arguments that are passed to it each time you call it.
05:31 We’ll solve this problem in the next lesson when you will learn about closures.
Become a Member to join the conversation.