Python for the .NET developer Transcripts
Chapter: The Python Language
Lecture: Python closures
0:00 We saw this idea of closures in C# was really
0:03 interesting and powerful.
0:04 Does Python have something like it?
0:06 Let's find out.
0:07 Over here, let's create one of these functions
0:09 that creates this counter, this closure.
0:11 So, we'll say def create_counter
0:14 and it takes a start_val
0:17 and a counter_id. So what did we do?
0:20 Well, we had a print statement, and then what did we do?
0:23 We defined a delegate type, didn't emphasize that
0:26 we had to create a delegate type and then we defined
0:28 a delegate instance.
0:30 Python you have this idea of these delegates as well
0:33 but it's much, much simpler.
0:35 You just define a function with exactly the same syntax
0:38 but indented so it's defined here.
0:42 We'll create a counter, which is a void function
0:45 say has a start, equals a start_val
0:48 it's going to start from that.
0:50 Maybe, it's going to increment.
0:53 We called it start before but it's kind of badly named
0:55 so we said every time you call it we're going to increment
0:57 this by one, and then we're going to print out
1:00 some kind of formatted string.
1:02 Like this, we're going to say the current counter_id is this
1:06 and we started at this
1:07 and now our current value is
1:08 whatever we've incremented it to.
1:10 Notice though, there's something a little bit
1:12 funny going on here.
1:13 We have these values that seem to be captured just fine
1:18 but this increment, there's something off with it
1:20 it says we don't know what that is.
1:22 And in order to tell this function
1:24 it's allowed to capture local variables
1:27 or even just to try to print it out
1:28 you have to use a new keyword, a nonlocal inc
1:33 and that says I'd like you to reach up to this
1:35 intermediate scope, it's not global
1:37 it's not defined here, and work with it.
1:39 Sometimes you have to use nonlocal, sometimes you don't
1:42 it's not entirely obvious when that is true
1:45 but down here we can return count, counter
1:47 not like this, that would call it, just the name.
1:51 So we're turning this function that was defined right here
1:55 and it's actually going to do closure
1:57 on these values just like before.
1:58 So let's go over here and say
2:00 counter1 = create_counter, start value
2:04 and we have 7 and the id was 1.
2:07 So let's just call counter a few times like that
2:09 we run this, and we run the right thing.
2:15 Look at that.
2:16 Counter with id 111 it's start value is 7
2:19 now it's 8, now it's 9, now it's 10.
2:22 Pretty cool, right?
2:23 So exactly like C#, except for we didn't have
2:27 to jump through hoops to specify the return type here
2:30 of whatever this delegate type that we're going to define
2:33 we just said no, here's a function
2:35 really more generally, there's something.
2:36 Here's a thing that can be called
2:38 'cause classes and other objects can implement
2:40 something along those lines as well
2:42 and then we just passed it back.
2:43 We also just had another one that was at -100
2:46 and this was id 2, that we said counter2, counter2
2:50 and then we did that three times.
2:53 Run it one more time, okay.
2:55 Counter id 1, 1 and 1
2:57 still goes from 7 to 8, seven to 9, 7 to 10.
3:01 And number 2 is going from -100 to -99
3:05 to -98, to -97, exactly like the C# closure
3:08 that we had before. Cool, right?
3:11 So, same thing if you have lambda expressions
3:13 or those little types of things
3:14 you can use closure to capture those values
3:16 into interesting things.
3:18 But just be careful because these values are remembered
3:21 they don't reset like normal functions.