Python Memory Management and Tips Transcripts
Chapter: Memory and functions
Lecture: Counting with closures
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
Well, that was pretty cool,
0:01
but let me show you how far this idea of closures goes.
0:04
There's something we can do that probably will be surprising if you haven't seen it.
0:08
So this is gonna be "counting_closure".
0:12
Start like this with our fmain as always.
0:15
Normally, what happens if you want to have some function and some data state that's
0:20
tied to it, you would create a class,
0:22
right? Classes have functions, they have fields and then they can create an instance
0:27
of them. You stick them together and they go around for the rest of their
0:30
life doing that. But let me show you that closures for a limited scenario,
0:35
basically, where there's one function but multiple pieces of data,
0:39
potentially, you can go around and do this same thing.
0:42
So I'm gonna write a function that creates another function, it creates a closure.
0:46
So, I'm gonna say "def create_counter",
0:49
and this function is going to return another function.
0:52
whose job is when you call it,
0:54
It's going to basically increment a counter by start from some position and have some step
0:59
size and so on. So I'll start, which is an int, step,
1:01
which is an int, and it's going to return a callable over here.
1:08
A thing you can call, basically a function.
1:10
Check this out. We're gonna go and say the current value is going to be
1:14
start minus step. Why did we do this minus?
1:18
Because the first thing we're gonna do when we define our function inside, check this is out,
1:22
it's not on the outer scope.
1:24
It's going to be the counter implementation. It takes no arguments,
1:29
and yet it works with data.
1:31
So what it's gonna do is it's gonna say "current += step" and it's gonna return
1:38
current. And because the first thing it does is increment it,
1:41
we want to go back one
1:43
so we start at the start, and then as soon as
1:45
we increment it, it goes step one back to where it was and then step, then
1:48
step, then step. Now, in order to tell it you want to use this
1:52
variable as a closure capture thing, you have to say
1:54
"nonlocal current". Now the warnings go away and what we're gonna do, we're gonna
2:00
return counter implementation without calling it.
2:04
Well, that looks kind of interesting,
2:06
But watch this. I'll say,
2:08
"create_counter" and let's say this one starts at 7 and it steps by 3.
2:14
Then we're gonna print out calling it c1 like this.
2:17
It's a function, it's a callable, so we do like this. And let's call it a
2:20
couple of times. What's gonna happen?
2:23
Well, the first time we've given it 7 and said to step by 3.
2:26
So hopefully it's gonna give 7.
2:28
But then what about the rest of these?
2:31
Is it going to remember where it was?
2:32
What is it going to do?
2:33
Let's just go and run this and find out.
2:37
Check that out. 7, 10, 13.
2:41
We could create another one of these.
2:42
We could create a c2,
2:44
which is create a counter, it starts at zero and
2:46
goes by 10. And let's just part way through
2:50
call c2 a couple times and I'll just say,
2:54
Make it a little obvious that these are the number 2's coming over.
3:01
Check this out. So it goes 7, 10 and this one just carries on, 13, 16,
3:06
and this other one I made also kind of seems isolated.
3:09
0, 10, if we called it a couple more times,
3:13
it would count up 10, 20, 30.
3:16
They have captured these variables and they hold onto them forever.
3:20
As long as c1 is around,
3:23
it's intermediate variables, like current and whatnot, those things now have references pointing back to
3:29
them. They're not going to get cleaned up. Even though this function returned,
3:33
and normally that would clean up this variable, It doesn't now. So,
3:37
the main take away from this section is that these functions can capture variables as a
3:42
closure, and when they do,
3:45
those captured variables are no longer released until the function goes away.
3:50
And if, you know, sometimes these functions would turn out to be top level
3:53
functions that never go away. So in some sense,
3:55
these could be like memory leaks.
3:58
That may be okay, that may not be okay,
4:01
but you need to be aware that when you capture these things through closure,
4:05
you're going to end up with possibly holding on to that data longer.
4:09
As you think about what things were getting captured,
4:11
you might want to think what variables do I really need here?
4:15
Are there times where I want to make sure they get cleaned up or something?
4:19
So this sort of takes you outside the bounds of normal cleanup for the variables and
4:24
pushes it back to the life cycle, the actual function that was
4:27
created as part of the closure.