1 00:00:06,070 --> 00:00:06,910 PROFESSOR: Hi. 2 00:00:06,910 --> 00:00:09,330 Today I'd like to talk to you about some notable aspects of 3 00:00:09,330 --> 00:00:12,660 Python that you'll encounter in the 6.01 software, as well 4 00:00:12,660 --> 00:00:15,640 as in the general sense when working with Python. 5 00:00:15,640 --> 00:00:19,160 A lot of these little tidbits of Python have some 6 00:00:19,160 --> 00:00:22,050 interesting history associated with them, especially related 7 00:00:22,050 --> 00:00:23,690 to the history of computer science. 8 00:00:23,690 --> 00:00:26,470 And also, I want to indicate some things that tend to mess 9 00:00:26,470 --> 00:00:29,270 up, especially, first time programmers, but also 10 00:00:29,270 --> 00:00:32,020 especially people that are new to Python. 11 00:00:32,020 --> 00:00:34,730 First, I'd like to bring us back to last week. 12 00:00:34,730 --> 00:00:37,140 We were talking about object-oriented programming 13 00:00:37,140 --> 00:00:37,930 and inheritance. 14 00:00:37,930 --> 00:00:40,830 Object-oriented programming is a programming paradigm. 15 00:00:40,830 --> 00:00:43,750 It's in the same category as imperative programming or 16 00:00:43,750 --> 00:00:45,000 functional programming. 17 00:00:45,000 --> 00:00:47,950 And you might say I have a good sense of the fact that in 18 00:00:47,950 --> 00:00:49,860 object-oriented programming, everything is an object. 19 00:00:49,860 --> 00:00:51,780 But I don't really have a good sense of what constitutes 20 00:00:51,780 --> 00:00:54,700 imperative programming or functional programming. 21 00:00:54,700 --> 00:00:56,310 I'm going to focus on functional programming right 22 00:00:56,310 --> 00:00:59,820 now, because it has more of a historic root in the academic 23 00:00:59,820 --> 00:01:01,810 development of computer science. 24 00:01:01,810 --> 00:01:04,819 Functional programming is like object-oriented programming in 25 00:01:04,819 --> 00:01:06,390 that everything is a function. 26 00:01:06,390 --> 00:01:10,080 It refers to the idea that you want to write as much of your 27 00:01:10,080 --> 00:01:12,880 code as possible in a purely functional manner. 28 00:01:12,880 --> 00:01:16,580 And in particular, you're looking for the ability to 29 00:01:16,580 --> 00:01:22,740 avoid things like side-effects or enable many different kinds 30 00:01:22,740 --> 00:01:25,210 of evaluation. 31 00:01:25,210 --> 00:01:27,160 Those kinds of things are not the subject of this course, 32 00:01:27,160 --> 00:01:30,910 but I think they're worth noting to figure out why we're 33 00:01:30,910 --> 00:01:32,830 bothering learning about things like lambdas and list 34 00:01:32,830 --> 00:01:35,760 comprehensions in the first place. 35 00:01:35,760 --> 00:01:38,210 Speaking of which, the first thing we need to talk about 36 00:01:38,210 --> 00:01:40,090 before we even talk about things like lambdas and list 37 00:01:40,090 --> 00:01:43,880 comprehensions, is the concept that in Python, 38 00:01:43,880 --> 00:01:45,440 everything is an object. 39 00:01:45,440 --> 00:01:48,440 But because functions are first-class objects, we can 40 00:01:48,440 --> 00:01:52,030 also treat Python to a large extent like a functional 41 00:01:52,030 --> 00:01:53,310 programming language. 42 00:01:53,310 --> 00:01:55,160 What do I mean when I say functions 43 00:01:55,160 --> 00:01:56,730 are first class objects? 44 00:01:56,730 --> 00:01:59,950 I mean that a function can be the return 45 00:01:59,950 --> 00:02:01,410 value of another function. 46 00:02:01,410 --> 00:02:04,550 I mean that the function can be passed in as an argument to 47 00:02:04,550 --> 00:02:05,400 a function. 48 00:02:05,400 --> 00:02:08,400 And I mean that functions can be assigned variable names and 49 00:02:08,400 --> 00:02:11,170 manipulated the same way that we manipulate any other piece 50 00:02:11,170 --> 00:02:12,730 of data structure. 51 00:02:12,730 --> 00:02:15,820 This is important, because if you want higher order 52 00:02:15,820 --> 00:02:19,840 functions or functions that actually modify or use other 53 00:02:19,840 --> 00:02:23,210 functions as a part of you know, whatever it is they do, 54 00:02:23,210 --> 00:02:25,320 then you need to be able to interact with the function 55 00:02:25,320 --> 00:02:27,930 like it's any other object, in part pass it in 56 00:02:27,930 --> 00:02:29,900 or return it out. 57 00:02:29,900 --> 00:02:31,480 Let's look at an example. 58 00:02:31,480 --> 00:02:37,290 So let's say I start off with a very basic function, right? 59 00:02:37,290 --> 00:02:40,140 If you want to square some sort of value, probably 60 00:02:40,140 --> 00:02:43,340 numeric in this case, then all you have to do is 61 00:02:43,340 --> 00:02:45,180 multiply it by itself. 62 00:02:45,180 --> 00:02:45,860 Pretty simple. 63 00:02:45,860 --> 00:02:47,110 Good place to start. 64 00:02:49,220 --> 00:02:52,160 As a consequence of the idea that functions are first class 65 00:02:52,160 --> 00:02:55,420 objects, I can write a function that takes in a 66 00:02:55,420 --> 00:02:59,650 function as an argument and then develops a return 67 00:02:59,650 --> 00:03:02,980 function that uses the function that I 68 00:03:02,980 --> 00:03:07,690 passed in, on itself. 69 00:03:07,690 --> 00:03:12,890 So any arguments that I would pass to someFunction, I would 70 00:03:12,890 --> 00:03:16,720 pass into someFunction, take the return value of this 71 00:03:16,720 --> 00:03:22,100 function call, and then pass that into someFunction again. 72 00:03:22,100 --> 00:03:25,170 That's what returnFunction does. 73 00:03:25,170 --> 00:03:29,240 And down here, I return returnFunction. 74 00:03:29,240 --> 00:03:31,710 Note that the object type of this 75 00:03:31,710 --> 00:03:34,060 return value is a function. 76 00:03:34,060 --> 00:03:36,950 So once I have returnFunction, I can actually pass it 77 00:03:36,950 --> 00:03:40,400 arguments, have them run through someFunction, not once 78 00:03:40,400 --> 00:03:45,550 but twice, and then get out a value that's of the return 79 00:03:45,550 --> 00:03:47,900 type of someFunction. 80 00:03:47,900 --> 00:03:49,530 Note that I made some assumptions while 81 00:03:49,530 --> 00:03:51,870 writing this function. 82 00:03:51,870 --> 00:03:54,960 First, I've assumed that someFunction returns out the 83 00:03:54,960 --> 00:03:58,530 same number of arguments, and either accept an arbitrary 84 00:03:58,530 --> 00:04:01,880 number of arguments or accepts the same number of arguments 85 00:04:01,880 --> 00:04:04,190 as it puts out. 86 00:04:04,190 --> 00:04:08,610 The other assumption that I've made is that the data type 87 00:04:08,610 --> 00:04:11,310 that someFunction returns is the same as the data types 88 00:04:11,310 --> 00:04:13,140 that someFunction accepts. 89 00:04:13,140 --> 00:04:17,870 Or the things that someFunction does to its 90 00:04:17,870 --> 00:04:20,930 arguments can be done to multiple kinds of arguments. 91 00:04:20,930 --> 00:04:22,430 But that's a whole different argument. 92 00:04:22,430 --> 00:04:27,990 Right now, we're just focusing on the fact that we pass in 93 00:04:27,990 --> 00:04:30,510 some arbitrary number of arguments, call someFunction 94 00:04:30,510 --> 00:04:34,990 on it, call someFunction again on the return value of this, 95 00:04:34,990 --> 00:04:39,520 and return that as something you can do to whatever it is, 96 00:04:39,520 --> 00:04:41,640 someFunction operates on. 97 00:04:41,640 --> 00:04:42,690 OK. 98 00:04:42,690 --> 00:04:44,450 Let's review an example, because I promise it'll be 99 00:04:44,450 --> 00:04:45,700 more clear. 100 00:04:47,910 --> 00:04:49,730 Let's say f is going to be the 101 00:04:49,730 --> 00:04:52,801 composition, a square on itself. 102 00:04:52,801 --> 00:04:59,780 If I do that, I end up with a function that operates on an 103 00:04:59,780 --> 00:05:01,030 arbitrary number of arguments-- 104 00:05:04,180 --> 00:05:05,560 that's not true. 105 00:05:05,560 --> 00:05:09,080 I end up with a copy of square that takes in the same number 106 00:05:09,080 --> 00:05:17,750 of arguments as square called on itself. 107 00:05:17,750 --> 00:05:22,940 So here a square is substituted for someFunction. 108 00:05:22,940 --> 00:05:26,690 Here a square is called on that call of square. 109 00:05:26,690 --> 00:05:28,100 And here is what f is assigned to. 110 00:05:31,350 --> 00:05:35,410 So when I call f of 2, I'm going to 111 00:05:35,410 --> 00:05:38,520 substitute 2 in for args. 112 00:05:38,520 --> 00:05:42,590 I'm going to call square on args. 113 00:05:42,590 --> 00:05:45,180 If I call square on args, I get out 4. 114 00:05:45,180 --> 00:05:50,980 And if I call square on args again, or if I call square of 115 00:05:50,980 --> 00:05:54,420 args where args is defined as the return value of this, then 116 00:05:54,420 --> 00:05:58,120 I'm going to call square on 4, I'll square 4, 117 00:05:58,120 --> 00:05:59,370 and I'll get 16. 118 00:06:01,820 --> 00:06:04,310 Take a second to type it into IDLE, and make it make sense 119 00:06:04,310 --> 00:06:05,130 to yourself. 120 00:06:05,130 --> 00:06:08,200 All of this code should compile. 121 00:06:08,200 --> 00:06:10,010 Mess around with the parameters, if you're having 122 00:06:10,010 --> 00:06:11,360 trouble convincing yourself that it does. 123 00:06:16,580 --> 00:06:16,665 Ok. 124 00:06:16,665 --> 00:06:19,660 Now I think we're ready to talk about lambdas. 125 00:06:19,660 --> 00:06:24,180 If you can pass in functions as arguments or return them as 126 00:06:24,180 --> 00:06:27,640 values or assign them to variable names and just treat 127 00:06:27,640 --> 00:06:30,300 them like any other data type, then you should be able to 128 00:06:30,300 --> 00:06:32,910 treat them as some sort of raw value. 129 00:06:32,910 --> 00:06:36,180 And that's where lambdas come in. 130 00:06:36,180 --> 00:06:39,430 Lambda is a key word in Python that tells you you're about to 131 00:06:39,430 --> 00:06:43,930 use a function that you have not given any sort of name or 132 00:06:43,930 --> 00:06:46,660 defined in any place in your code or environment 133 00:06:46,660 --> 00:06:47,190 beforehand. 134 00:06:47,190 --> 00:06:49,910 You're just going to start talking about something that 135 00:06:49,910 --> 00:06:52,990 you would like to do to a given number of arguments, and 136 00:06:52,990 --> 00:06:55,740 then what you want to return out. 137 00:06:55,740 --> 00:06:59,720 Lambda has roots in lambda calculus which, if you're 138 00:06:59,720 --> 00:07:01,300 familiar with the history of computer science, you've 139 00:07:01,300 --> 00:07:02,850 probably heard of. 140 00:07:02,850 --> 00:07:05,070 Now might be a good time to look up lambda calculus, if 141 00:07:05,070 --> 00:07:08,730 you've never heard it before or possibly Alonzo Church. 142 00:07:08,730 --> 00:07:12,960 But it's still available in code today, which is really 143 00:07:12,960 --> 00:07:17,610 cool, and speaks to the continuing power or at least 144 00:07:17,610 --> 00:07:20,360 recognition of importance of functional programming. 145 00:07:23,360 --> 00:07:26,460 As I said before, the idea with lambda is that you could 146 00:07:26,460 --> 00:07:28,740 write an anonymous function. 147 00:07:28,740 --> 00:07:36,260 Over here, in order to write a function that's squared, I had 148 00:07:36,260 --> 00:07:38,200 to write out a define line. 149 00:07:38,200 --> 00:07:41,690 And because Python uses indentation, because in 150 00:07:41,690 --> 00:07:45,000 Python, indentation carries meaning, I'd have to enter and 151 00:07:45,000 --> 00:07:47,012 return over to a next line-- 152 00:07:47,012 --> 00:07:48,730 I'm actually not sure if that's strictly true. 153 00:07:48,730 --> 00:07:50,620 I think you can do def square x, return 154 00:07:50,620 --> 00:07:54,240 x, but I'm not positive. 155 00:07:54,240 --> 00:07:56,210 I've only seen it written like this. 156 00:07:56,210 --> 00:07:58,810 And I think it's because in the general sense, people try 157 00:07:58,810 --> 00:08:01,060 to respect things like convention and 158 00:08:01,060 --> 00:08:02,310 readability in Python. 159 00:08:04,940 --> 00:08:08,070 If you're using lambda, people already know that you want to 160 00:08:08,070 --> 00:08:09,480 describe a function really quickly. 161 00:08:09,480 --> 00:08:10,920 Or you want to describe function without 162 00:08:10,920 --> 00:08:13,600 assigning it any name. 163 00:08:13,600 --> 00:08:17,270 Therefore, the two most common uses you'll see of lambda is 164 00:08:17,270 --> 00:08:19,430 when you want a really fast function and you don't want to 165 00:08:19,430 --> 00:08:22,500 spend extra time or lines writing out that function. 166 00:08:22,500 --> 00:08:26,340 It's pretty clear what this is going to do. 167 00:08:26,340 --> 00:08:29,020 Or if, in a particular sense, you need 168 00:08:29,020 --> 00:08:30,120 an anonymous function. 169 00:08:30,120 --> 00:08:33,380 You don't want to assign a name or memory space 170 00:08:33,380 --> 00:08:34,630 associated with that function. 171 00:08:38,669 --> 00:08:42,820 Note instead of using square, I can just write out this. 172 00:08:42,820 --> 00:08:45,830 So I saved two lines of code defining square. 173 00:08:45,830 --> 00:08:48,680 And then I don't have to refer back to some earlier part of 174 00:08:48,680 --> 00:08:49,890 the code in order to understand 175 00:08:49,890 --> 00:08:51,570 what this line does. 176 00:08:51,570 --> 00:08:53,520 Pretty cool. 177 00:08:53,520 --> 00:08:54,960 All right. 178 00:08:54,960 --> 00:08:57,650 So there's functions of first class objects. 179 00:08:57,650 --> 00:08:59,350 There's lambda. 180 00:08:59,350 --> 00:09:01,535 Let's talk about how to use lambdas on lists. 181 00:09:08,450 --> 00:09:12,770 In Python, you'll end up doing a lot of list manipulation. 182 00:09:12,770 --> 00:09:19,190 One of the best uses of anonymized functions in any 183 00:09:19,190 --> 00:09:21,480 functional programming language is the ability to 184 00:09:21,480 --> 00:09:23,010 manipulate lists in a line. 185 00:09:26,550 --> 00:09:29,820 If I've defined just a pretty straightforward list right 186 00:09:29,820 --> 00:09:36,700 here, I can use functions like map filter and reduce to-- 187 00:09:36,700 --> 00:09:38,150 in one line-- 188 00:09:38,150 --> 00:09:42,420 take a list, apply a function to every element in that list, 189 00:09:42,420 --> 00:09:48,020 and then return a copy of the result of that list. 190 00:09:48,020 --> 00:09:50,060 I didn't have to write a separate function to do the 191 00:09:50,060 --> 00:09:52,020 list handling. 192 00:09:52,020 --> 00:09:54,405 I didn't have to write a separate function to multiply 193 00:09:54,405 --> 00:09:57,600 the list by two. 194 00:09:57,600 --> 00:09:59,940 And I've communicated what I'm doing effectively to people 195 00:09:59,940 --> 00:10:01,190 that are used to functional programming. 196 00:10:04,100 --> 00:10:08,920 So if you type this line in, you should end up with a 197 00:10:08,920 --> 00:10:12,640 return in interactive mode of every element in this list 198 00:10:12,640 --> 00:10:13,860 multiplied by two. 199 00:10:13,860 --> 00:10:16,210 Now's a good time to try. 200 00:10:16,210 --> 00:10:19,820 Once you've done that, I also recommend looking at the 201 00:10:19,820 --> 00:10:21,750 original copied demolist. 202 00:10:21,750 --> 00:10:23,910 Note that this is unaltered. 203 00:10:23,910 --> 00:10:30,080 Map actually returned a new data structure that represents 204 00:10:30,080 --> 00:10:34,430 performing this function on this list. 205 00:10:34,430 --> 00:10:36,910 This becomes important later when I explain aliasing, but I 206 00:10:36,910 --> 00:10:38,830 will do that in about two minutes. 207 00:10:43,930 --> 00:10:47,460 If we want to get even more elegant, we can use list 208 00:10:47,460 --> 00:10:48,710 comprehensions. 209 00:10:50,400 --> 00:10:51,990 List comprehensions-- 210 00:10:51,990 --> 00:10:54,030 if you ask somebody where list comprehensions are from, 211 00:10:54,030 --> 00:10:56,580 they'll probably say Haskell, because that is the most 212 00:10:56,580 --> 00:11:00,370 popular use of list comprehensions, in terms of 213 00:11:00,370 --> 00:11:03,450 pure lazy functional programming. 214 00:11:03,450 --> 00:11:06,990 But it actually goes back further than that, and is in 215 00:11:06,990 --> 00:11:09,290 Small Talk, and then something from the '60s. 216 00:11:09,290 --> 00:11:10,740 I can't remember the name of it right now. 217 00:11:14,620 --> 00:11:30,630 They're really nice because they borrow a syntactic 218 00:11:30,630 --> 00:11:32,830 approach from mathematicians. 219 00:11:32,830 --> 00:11:35,600 This looks a lot like set notation. 220 00:11:35,600 --> 00:11:39,180 And when you read this, you can probably tell that the 221 00:11:39,180 --> 00:11:44,000 list listComprehension is going to describe a set of 222 00:11:44,000 --> 00:11:46,970 points from 1 to 4. 223 00:11:51,910 --> 00:11:55,980 But you accomplish that in possibly one line of code. 224 00:11:55,980 --> 00:11:59,080 I've written it on three here because I wanted to keep it in 225 00:11:59,080 --> 00:12:00,540 this space. 226 00:12:00,540 --> 00:12:04,790 But it's really concise. 227 00:12:04,790 --> 00:12:07,330 If you type this into IDLE, you should see the kind of 228 00:12:07,330 --> 00:12:10,010 list that it returns, and also what's 229 00:12:10,010 --> 00:12:11,660 listComprehension is now-- 230 00:12:11,660 --> 00:12:12,910 what now constitutes listComprehension. 231 00:12:15,320 --> 00:12:20,690 You can use listComprehensions with functions like map and 232 00:12:20,690 --> 00:12:23,330 filter and reduce. 233 00:12:23,330 --> 00:12:27,810 And, along with the anonymized functions, all of these tools 234 00:12:27,810 --> 00:12:29,890 provide you with a lot of functionality in a very short 235 00:12:29,890 --> 00:12:31,140 amount of space. 236 00:12:33,450 --> 00:12:36,280 It's also good to be able to recognize what's going on when 237 00:12:36,280 --> 00:12:39,530 you see something like this or something like this. 238 00:12:39,530 --> 00:12:41,940 Because you'll probably run into it in, in particular, a 239 00:12:41,940 --> 00:12:46,860 lot with Lisp code, but also in the artificial intelligence 240 00:12:46,860 --> 00:12:48,110 community in particular. 241 00:12:52,160 --> 00:12:52,245 Ok. 242 00:12:52,245 --> 00:12:55,400 We've talked about all that. 243 00:12:55,400 --> 00:12:58,210 Let's take a second to talk about the fact that lists are 244 00:12:58,210 --> 00:13:01,710 actually mutable, and what that means, and what things 245 00:13:01,710 --> 00:13:03,670 you have to be careful about if you're going to be working 246 00:13:03,670 --> 00:13:04,920 with mutable objects. 247 00:13:09,500 --> 00:13:11,640 If you're new to programming, or you're new to Python, 248 00:13:11,640 --> 00:13:13,020 you've probably already worked with some of 249 00:13:13,020 --> 00:13:14,600 these data types, right? 250 00:13:14,600 --> 00:13:18,000 Any numbers, any strings, any tuples, 251 00:13:18,000 --> 00:13:20,610 are going to be immutable. 252 00:13:20,610 --> 00:13:26,920 What that means is if you have a variable and you have a 253 00:13:26,920 --> 00:13:31,210 second variable that has a different assignment line 254 00:13:31,210 --> 00:13:32,370 associated with it-- right? 255 00:13:32,370 --> 00:13:34,640 I haven't assigned g to h here. 256 00:13:34,640 --> 00:13:39,000 I've just signed g to "hello" and h to "hello." 257 00:13:39,000 --> 00:13:43,610 If you look at the space in memory that Python associates 258 00:13:43,610 --> 00:13:48,000 with both objects, they point to the same place. 259 00:13:48,000 --> 00:13:51,140 This is the definition of an immutable object. 260 00:13:51,140 --> 00:13:54,110 When g points to "hello" and h points to "hello," they both 261 00:13:54,110 --> 00:13:55,010 point to the same place. 262 00:13:55,010 --> 00:13:58,040 If x points to 5 and y points to 5, they're both pointing to 263 00:13:58,040 --> 00:13:59,940 the same place. 264 00:13:59,940 --> 00:14:03,120 If you point x at 6, it now points to a 265 00:14:03,120 --> 00:14:04,370 different memory address. 266 00:14:08,460 --> 00:14:10,180 This gets confounded when you're talking 267 00:14:10,180 --> 00:14:11,940 about mutable objects. 268 00:14:11,940 --> 00:14:14,670 The problem with mutable objects is that you select a 269 00:14:14,670 --> 00:14:19,180 memory space to contain the object or memory ID in Python 270 00:14:19,180 --> 00:14:20,500 to contain the object. 271 00:14:20,500 --> 00:14:25,090 And then that object is changed in place. 272 00:14:28,460 --> 00:14:30,290 You can use this to your advantage but it can 273 00:14:30,290 --> 00:14:31,120 also mess with you. 274 00:14:31,120 --> 00:14:32,680 And here's how. 275 00:14:32,680 --> 00:14:37,160 Let's say I assigned a to a small list. 276 00:14:37,160 --> 00:14:41,100 And I also assigned b to a. 277 00:14:41,100 --> 00:14:42,835 b and a now point at the same place. 278 00:14:45,660 --> 00:14:48,540 If I manipulate b, and I'm-- 279 00:14:48,540 --> 00:14:51,309 excuse me-- still working with an immutable object, or excuse 280 00:14:51,309 --> 00:14:58,660 me, if I'm still working with a mutable object, the object 281 00:14:58,660 --> 00:15:01,100 in that memory address has been altered. 282 00:15:01,100 --> 00:15:05,740 And b and a still point to the same place in memory. 283 00:15:05,740 --> 00:15:10,740 So if I look at a, it's going to look like b, which is going 284 00:15:10,740 --> 00:15:12,990 to look like 1, 2, 3, 4 -- 285 00:15:12,990 --> 00:15:16,230 which is not what I assigned a to originally. 286 00:15:16,230 --> 00:15:19,000 Again, can be powerful, but you have to keep it in mind. 287 00:15:19,000 --> 00:15:22,160 And it might start to mess with, in particular, the 6.01 288 00:15:22,160 --> 00:15:26,620 software when you're dealing with state machines. 289 00:15:26,620 --> 00:15:29,220 In order to get around this, you can create a copy of the 290 00:15:29,220 --> 00:15:31,500 list and then modify the copy. 291 00:15:31,500 --> 00:15:34,230 This is actually what map does. 292 00:15:34,230 --> 00:15:36,610 If you want to do it, the easiest way to do it on the 293 00:15:36,610 --> 00:15:40,120 first layer is to specify the index into the 294 00:15:40,120 --> 00:15:42,360 list with no bounce. 295 00:15:42,360 --> 00:15:43,770 It'll copy the whole thing. 296 00:15:43,770 --> 00:15:48,430 There's also a Python library copy or deep copy, if you want 297 00:15:48,430 --> 00:15:50,890 to copy lists of lists of lists of lists of lists. 298 00:15:53,420 --> 00:15:58,690 And just to clarify, you'll note that after you assign c 299 00:15:58,690 --> 00:16:02,780 to a copy of a, c and a occupy different memory places. 300 00:16:02,780 --> 00:16:07,096 So if you modify c, a will retain its original value. 301 00:16:11,070 --> 00:16:12,300 I think that's all the notable things I have 302 00:16:12,300 --> 00:16:13,250 to say about Python. 303 00:16:13,250 --> 00:16:17,200 and gives us enough power to do some really powerful list 304 00:16:17,200 --> 00:16:21,980 manipulation or array manipulation, and covers what 305 00:16:21,980 --> 00:16:23,740 we want to say about functional programming before 306 00:16:23,740 --> 00:16:26,410 we get into the notion of state, which I'll 307 00:16:26,410 --> 00:16:27,660 talk about next time.