Lecture 8: Functions as Objects
Skills:
Algorithm Basics70%
Key Takeaways
This video lecture covers functions as objects in Python programming, focusing on the basics of functions, function definitions, and function calls, with an emphasis on understanding functions as first-class objects in Python.
Full Transcript
All right, everyone. So, let's get started. Last lecture we introduced functions and we saw some syntax around how to create functions, but mostly we were interested in kind of motivating functions as a way for us to start writing really clean code, code that's easy to debug and code that's easy to read in the future. Today, we will continue our fun adventure with functions and we'll see how what it means to treat functions as objects. So, let's recall the example we talked about last lecture. We created this function is even. So, the syntax for creating a function is basically the keyword d e f tells Python we're defining a function. We decide what name to give our function, parentheses tells Python in here we're going to name all the arguments, all the inputs to the function. The colon starts the body of the function. The first part, it's not required, but should always kind of be in there as a way for us to implement abstraction is the called the doc string. So, this in green is the doc string. Triple quotes starts our doc string and triple quotes ends the doc string. And you think of the doc string also known as a specification as just a really long comment. Okay? And in it, it's and and the doc string is kind of I called it a contract between the person who writes the function and a person who uses the function. And in the contract, the person who writes the function basically says, "This function is going to take these inputs and I guarantee this function to work correctly when you give me these inputs of these types and these restrictions on them, things like that." And then you also state what the function is going to do. And then you also state what the function will return. Okay? In this particular function, we have only one line. This is the body of the function, but you've hopefully seen functions that are a little bit longer as you did the practice from last lecture. Um and the body of the function itself, so the lines of code are basically lines of code that we've seen before. Okay? There's nothing sort of special about that except for lines that start with a return. So, lines that start with a return basically tell Python that as soon as I see this line with a return hit in when I'm executing my function, I need to stop executing this function, take the value associated with this return and pass it back to whoever called me. Okay? A function always returns something. Okay? In this particular case, the function will return either true or false, a boolean, but you can write functions that return integers, floats, strings, things like that. In this case, yeah, this is what is is returned. It is possible and we actually saw this in one of the you try it as we were writing our code. It is possible to write a function that doesn't actually return anything explicitly. So, here is the is even function and inside the body, the only change I've made is I've eliminated the little return keyword, but otherwise the work that is done is the same. So, here I'm just calculating whether the remainder is zero or not. So, this line of code when the the when the function is executed just is replaced with either true or false. Okay? Notice this function doesn't have a return keyword, but all functions return something. So, while function is being executed because of a function call if the function reaches the end of all of these indented lines here, right? Everything that's indented if it reaches the end and no return statement has been hit then Python automatically returns none. Okay? So, this is the line without a return statement. You can think of this code as basically behind the scenes Python putting this little line at the bottom that says return none. Okay? Now, this is not something that we would ever write. You just do the operations, maybe you print some stuff out and then you just omit the return keyword if you want to return none from the function. Okay? And none is this none type is is of a value that is of type none type. We talked about it back in maybe lecture one or two and we haven't really used it that much since. But basically, you think of it as just having the type none type and there's just one value associated with it, none. And usually we use this value to represent the absence of a value in our code. So, let me just run some code first just to show you exactly some of the kind of things you might observe when when you write code that doesn't have a return statement. So, here I promise this is the last time we're going to see is even. Um so, here I have two versions of the is even function. So, I have one that I named is even with return and I have one that is named is even without return. Okay? They do very similar things. The difference is that this one has a return statement where I return whether the remainder is equal to zero and this one has no return statement but it just prints whether the returns the remainder is equal to zero. Okay, so let's look at running the code with is even with return and as we're doing so, this first function will be a recap of last lecture, kind of tracing through what happens when we make a function call. So, I've uncommented this line and now I'm running line 13. Okay? So, when Python sees this file, it basically sees this function definition. And this is not code that runs yet, right? It's just telling Python that I've created this function inside memory. When I have this line being run, that's when the function is actually being called and actually being run. So, I is replaced with a parameter three. And at this point, the body of the function is executed. So, the first thing that we tell the function to do is print the string with return. So, if I run it, you'll see it prints with return. Then it calculates this variable remainder, which is going to be one, right? Cuz 3% 2 equals 1. And then I'm going to return whether one equal equal zero. So, that's going to be false. So, as soon as we see this return statement, Python returns out of this function call and replaces the function call entirely with the return value. So, this entire line after the the function call is executed is replaced with false. So, I've just noted that here. We're not doing anything with this return, right? All we're doing is making the function call and it just kind of sits on line 13. In order to see the result of the function call, we saw last lecture that we actually wrap the function call around a print statement. Right? And function calls in that sense are kind of just expressions, right? They do some work. Python evaluates them to some value and then replaces that function call with the value. So, if we wrap is even with return three, this function call around with a print statement Python does the whole thing again. I is three. It returns false and this line effectively becomes print parentheses false and we know what that does, right? It just prints false to the screen. And there it goes. Right? Notice we still did this print statement because as part of the function body, we tell it to do this print. Everyone okay so far? Okay. So, now let's see what happens when we run this function is even without return. So, very similar. I've just created an extra parameter here or variable here just to show you that you can. Um so, this function is even without return three is being run on line 27. So, I is three. This function will print without return and then it calculates remainder to be one and then has rem will be false, right? So, the variable has rem will have a value of false. And then as part of the function body, we're going to print the value of has rem, which is false. So, this line here will actually print for me without return and then this thing, false. Okay? And then the function has no return statement explicitly in there. So, you think about it like Python kind of implicitly adds this return none at the end of it the function call. We don't add this. I just wrote it there just to show you that Python would add a line such as this when it reaches the end of the function but you would never add it. So, that means that the entire function call is replaced with none. Okay? Yeah. So, when you what happens when you put print in the definition versus when you put return What happens when you put print in the definition versus around the function call? Versus like when you put return in the definition. Versus when you put return in the definition. So, that's the next line. So, in the next one if we were to do what we did before, which is let's print the result of the function call well, Python will do everything we just did, right? So, it'll print without return. It'll print false. But then, it'll additionally print the return from the function call. So, if the return is none, this line effectively becomes print none. So, what we end up seeing or what the user would end up seeing if they actually run this program is they'll see without return, they see a false, and then they see this extraneous none in the console, right? So, you'll see probably this in problem set two. You'll probably encounter an error such as this in maybe problem set three. But don't be scared. Whenever you see a none out in the console, it just means you have to be careful about the function that was called, right? You probably forgot to return something and instead we're we're just, you know, printing the correct value within the function, but just never returned it, right? So, that's just uh something to be wary of. Should you always use return instead of the definition of it? Yeah, so that's a good question. Should you always use return? It depends on what you want in the function to do. Most functions are useful because they go off on their own, they do a task, and they get a value at the end, and they pass the value back to whoever called it. And then you can use that function with many different inputs to give you many different outputs. So, usually you'd want to make functions that return something that you can then do something else with further in a in another part of the program. The The The prints within the within the functions should usually be maybe for debugging or for, you know, like maybe the status of the function, you know, what part is it's executing or something like that. Okay, and then when you run the function, then it will give you the return, but if you print in the function, that's when it does the none. Exactly. Yeah, if the function's not returning anything, then it'll do it'll print none. Okay. Right. Yeah. But if the function's returning something, it will print, right, this if you wrap it with a print, it'll print whatever got returned. Okay. So, let's have you uh work on this. Actually, there's nothing to to write, but think about it. So, I've got four lines of code here. Add one {comma} two, print wrap that around the print statement, mult three {comma} four, and then add add that around a print statement. So, try to trace through and tell me what outputs um each each function call will give me, right? So, add one {comma} two, what happens? What do you think the output of this function is? What gets printed to the screen? What is it? Addition. This is three. Am I telling it to print anything? That's the question. Yeah. So, nothing is actually printed to the screen, right? Because in the function call add {comma} two, right? We basically map the parameters one at a time. X is one, Y is two. That was good. We return three. And so, this entire function call is replaced with three. But we never told the the that line of code to print that result, right? So, there's nothing printed in this case. Well, what if we wrap uh this in a print statement? Is anything printed in this case? Yes. What is printed? Five. Yeah, exactly, right? The add itself gives me five, and so I'm telling it to print five. What about the next one? Mult, what is that? Four three four. Is anything printed as a result of running this line? No. I heard some yes, some no. Yeah, the print is in the function, exactly. So, just because it's a function call doesn't mean we don't print anything, right? We need to check out what the function is actually doing. So, in mult, um X gets mapped to three, Y gets mapped to four, and the function body itself says to print the result. So, this will print as a part of the body, right? Um prints the 12. Anything else it prints? No. And lastly, what if we put a print statement around the mult four five? What will that print? Yeah, exactly. 20 then none. So, the mult itself is going to print same as there, it prints the 20. So, the function call returns none. So, this entire function call basically is replaced with none, and the line then becomes print none. So, this will print uh the none to the screen. So, there's actually four uh four printouts generated from these four lines, right? The first one generates nothing, but the last one generates two lines of printouts. Any questions about this example? Yes. Can you go over why it prints out the none? This one here? Yeah, so the mult um check out what it's doing. It's doing a print statement, so that uh 20 gets printed out to the console. But what's the return value of mult? There is no return, right? So, if there's no return, Python adds the none. Right? That's just something that's implicitly done. So, the return from mult, because it doesn't actually have an explicit return, is none. So, we're asking it to print the return, which is none. Okay. So, a couple words on return versus print. So, the return only has a meaning inside a function. So, as an example, if I just have this uh file open and I have return five just randomly that's not within a function definition, already I'm in trouble. You see that red X. And if I run that code, Python gives me a syntax error. This one's pretty easy to debug. There's a return outside of a function. Yep. There it is. Okay. So, return only has a meaning inside a function. It basically says this function has done some work for me, and it's returning back this value. Print statements can be put wherever you'd like, inside functions, outside functions, wherever you'd like, and they all get executed. You can have many return statements inside a function, like if you have a function that returns zero if some condition applies or one if some other condition applies, then you can have those two return statements. But as soon as Python during execution hits one return statement, it immediately ends the function, takes that return value, and pops it back to whoever called it, okay? So, it's not going to run more than one return uh statement. Print, on the other hand, you can run as many print statements as you'd like inside the the program, right? And they can all be hit. Um and they can all generate some sort of output to the console. Um So, the return statement has a value associated with it, right? So, return five, return, you know, we had remainder equal equal zero, whatever. There's that associated value with that return statement. That value is what gets passed back to whoever called the function. The print statement also you can think of it as having a value associated with it. That's the thing that gets put out to the console. But that value associated with the print statement is is just something that's outputted to the console. It's not being passed around through the program at all. It's just kind of static, it gets put to the console, and then that's it. Nobody else can really use that value, you know, unless it's a variable and then you're just using a a regular variable. The last thing I want to show you, this is kind of cool. So, if we have a print statement, right? Just in here, and we run it, obviously that prints that to the console. But what is this print? It's a function, right? It has all the telltale signs of a function. The name is print. The parentheses are there, and I'm giving it one parameter, five. Right? So, if I print the return of the print function. So, if I wrap my print function in another print function, what do you think this is going to output? I'll run it. It outputs none. So, the first five is due to this. This shows up on the console. But print being a function, it doesn't actually return anything, right? It does something useful, like take whatever you want and show it on the console, but it doesn't return anything back to whoever called it. And so, if I wrap my print function around another print function, I'm basically printing the return of the print function, which is none. So, that's where the second none comes in. Right? So, thought of another way, you can make a variable A equals print five, and if I print A, basically we're saying the return of that print first print function is just none. Yeah. Oops. Okay. So, I'm going to have you work on this code for a little bit. Uh nothing to write, but there is something to fix. So, here's a function called is triangular. It takes in one parameter n, it's a number, an integer greater than zero. I want this function to return true if n is triangular and false otherwise. So, triangular just means it's a whole number uh such that it's equal to 1 + 2 + 3 + some, you know, some some summation like that. Right? So, one is triangular, three is triangular, uh six is triangular, and so on and so on. So, take a look at this code. Um it's online around 49-ish. So, start by running it, seeing what you get, and I'll give you about a minute or so to see if you can try to fix it. Okay? So, make sure it runs with all these test cases here. Okay, what's the first thing you should do when you're asked to fix some code that's buggy? Yes. We can do that, but first let's run it with something, right? Um So, let's run it with the first one. Print is triangular four. So, we know the answer should be false. I mean, I I told you, so that's good. Um yes, it does give me false, which is good, but it also prints out a none. What does that mean for us? Yes. Yeah, exactly. Perfect. So, there's no actual return statement, right? Like I mentioned in with the is even example, if you're seeing some nuns show up in places, check your returns. So, is this function actually returning something? No, it's just printing the the result. So, it's printing the right thing in this case, right? So, let's start by changing the prints to returns. Right? Yeah. For this one? Yeah. Oh, never mind. Okay. All right, let's run it. Perfect. Yeah. So, that seems to have fixed it. Um what should we do next? Yes. We should check the rest of the print statements if it doesn't work for one. Yes, exactly. Let's check the rest of the print statements. So, the second one, six is triangular, so that prints true. And last one, as you mentioned, is going to fail on us. It prints false, but one is triangular, right? Because one is just the sum of one. So, do you know what a fix could be? Uh the range is to n + 1. Yeah, exactly. So, you've you've spotted it. The range should be n + 1. If you didn't spot that right away, um as I think somebody mentioned there, the first thing we should do is just start putting some print statements. And inside the loop is a great place to put a print statement. We can see what thing we're iterating over. Right? And so, if this was still n and we didn't manage to fix it and we run it, we see that we've iterated when I is zero, right? Right here. And we never actually hit on hit one. Right? So, the fix for that is make sure we go up to and including n. And now if we run it, and remove this print statement because it might be a little confusing, that now gives me the correct answer. Last step should probably be to run the other two cases again, just in case my fix broke something else. And it didn't. The other two cases are still the same. Questions about this code? Does it make sense? Okay, so now last lecture I mentioned that once we write functions, it's really easy to include these functions in larger pieces of code, and it makes those larger pieces of code very nicely readable. So, let's try to do the same with a slightly more complex example. Let's try to do uh to create take our bisection root code, right? And make it into a function. And then there's going to be an exercise in a couple slides where you get to use this uh this function. So, the inside of this uh function here is basically what we had like three lectures ago. Okay? It's just the bisection square root code. The only thing I've done is I've wrapped it around a function definition. So, d f, I gave it a name, bisection root is a pretty nice name, and figured out what input this function should take. So, the input should be the x I would like to approximate the square root of. Right? Um one thing I didn't do is put a docstring on this. So, that's my bad. Uh but, you know, the docstring would say x is a positive integer greater than one and returns the approximation to the square root of x or something like that. Um Okay, so here we're hardcoding epsilon to be .01. Uh we've got our low and high endpoints, right? Just remembering what the bisection root does, and we're starting out with a guess that's right in between the low and highs. The while loop here is going to do the work for us. So, the while loop condition is while the difference, the absolute value, right? The difference between our guess squared and the actual x we're trying to find the square root of is bigger than epsilon. So, while we're still farther away than epsilon, we have more guesses to make. The way we make the guesses is by updating the low endpoint or the high endpoint, right? Depending on whether our guess was too low or too high. This should be review, hopefully. And then after we've decided on which endpoint to update, we update our new guess to be whatever high plus low is divided by two again, so the midpoint of those, where either high or low would have just changed, right? Because of this if else. And this loop will just keep going over and over and over again, making better and better approximations until we come within plus or minus epsilon of uh the square root of x. of x. The difference between this code and what we wrote a few a few lectures ago is this uh part down here. So, a few lectures ago, we all we could do really was uh write a print statement, where we took our guess that we ended up with, right? And we printed it along with, you know, that guess is close to the root of our original x. But instead, since we're writing a function, I would like to take the result, right? My approximation to x, and return it. So, somebody can call this function many, many, many times with different values of x and figure out a bunch of different approximations for all of these different x's. So, here I have the function calls, right? So, I've got bisection root with four and bisection root with 123, and then I can just print the results of these, right? So, here is the bisection root function. I've got my printout uh commented out because I don't actually need it. Uh the rest of the code will do something useful with the approximations, right? So, in this case, bisection root of four was uh gave me a 2.0, so that's the approximation, and the bisection root of 123 uh was approximated to 11.09. Okay. So, what I would like you to do, and this is going to be a little bit involved code, it'll require some thinking, is to write a function called count the numbers with the square root close to n plus or minus epsilon. Okay. And I'll I'll I'll help you out by drawing something on the board, but I would like you to do uh the code for it. So, the idea here is that you have some n that's given as an input, and you have an epsilon that's also given as an input. What you'd like to find out is how many whole numbers have their square root within plus or minus epsilon of n. So, this is kind of hard to wrap your mind around without actually drawing a picture. So, this is also something you should try to do in quiz situations, psets, things like that. Don't code right away. Try to draw a picture kind of depicting what we're asking for here. So, here we'll start with a line. Right? This is our number line cuz we're doing the square root. We want to know how many integers have a square root within epsilon of n. So, let's start with an n, right? And we have something plus or minus epsilon, right? So, this is epsilon, and this is also epsilon. In the end, we want to know how many integers have a square root square root of i. So, actually I'll I'll it like this. Square root of I is equal to somewhere in this range. Does that make sense so far? That's what we're trying to figure out. The square root of I is somewhere in this range. So, that means I is going to be some giant number out here. Right? So, this line can go further out. So, in the example here, I've got n is equal to 10. So, I know for sure that an I of 100, just kind of us as humans, would work. Right? Because the square root of 100 is probably going to be approximated to pretty darn close to to 10. So, I know that that value will be within plus or minus epsilon of 10. But, there's probably a couple numbers around 100 that also match this criteria, right? If I take the square root of 99, according to this example, that approximation puts me within plus or minus epsilon of 10, right? So, it's going to be you know, square root of 99 is going to be like 9. Whatever is here. 9.5 Right? So, that's within plus or minus epsilon. And similarly, right? Square root of 101 and 102 also work. Because if I take the square root of these guys, that will also put me within plus or minus epsilon of 10. So, the goal here is basically to figure out these numbers, 99, 100, 101, and 102. You should use the power of computation and computers being able to do a a task really really quickly to basically say, "I'm just going to brute force my way through this problem and say, I'm going to test each number one at a time all the way up to some pretty large number, right? So, you want to make sure you hit 99, 100, 101, 102. Maybe going up to maybe n cubed, right? If you go and take the square root of some I cubed, you know you're going to hit all these values within plus or minus epsilon. So, you're just going to brute force, look at all the integers between 0 and n cubed, and figure out if this if their square root, the approximation of the square root is within plus or minus epsilon of n. If it is, keep a counter and increment it, and if it's not, ignore it. And that's the idea to this um to this question. Loop and a check. That's it. And you can definitely feel free to make use of the bisection root function that we wrote uh in in our code, right? You should definitely use it cuz it's very helpful. So, around line 96 is where you can write your code. All right, does anyone have a start for this uh for writing this code or how would you think about it or Yes. Um for I For I in range uh n cubed. Yeah, we can do that. All right, so this will give me numbers 0 through n cubed. Perfect. So, I've generated basically this sequence now. What do I want to do once I have I? And you know, you can always write a little comment for yourself or what you want to do once you have I. Right? So, in English, what would you want to do once you have a number like this? Take the square root, yeah. Take the square root of I. Okay? How do you want to take the square root of I? We can. Shall we use our bisection root? We can, too. Yep, we can do both. So, let's use the function we just wrote. So, bisection root of I, this gives me square root. So, now sqrt is going to be some value here, right? It could be 10, it could be 99.5, it could be 99.7. What do I do with this number now? Yes. Yes, exactly. Let's use an if statement. So, if, and there's many ways we can if if use the if statement, we could do absolute value, right? That's what we've been doing already. So, if we take um n minus the square root, right? So, n minus this value we just calculated is less than epsilon. All right, so here we know that um square root is within epsilon. And what do we want to do once we know that the square root is within epsilon? Well, if we don't know, we can look at the doc string. So, we need to return how many integers have that square root within epsilon of n. Yeah, exactly. Keep count of it, right? So, count plus equals one. Yes, and I do have to initialize count. Count equals zero, right before my loop. Okay. Anything else? Yeah, we do need to return. So, at the end of the loop, we can return our count. Okay, run it. Uh what is this from? Oh, this is from the other two lines here. So, four. I think that works because from the example, there were four numbers that worked. To double-check, we can or if you know, something went wrong and the number you got wasn't what you were expecting, again, print statements very useful. So, we could print the value of I, so this thing here we're trying to find the square root of, and we can print the square root of that value, right? And so, if we actually add it to the print statement uh to the to code here, we see the four values that we grabbed, 99, 100, 101, and 102. And now that we wrote this code, we can actually make really uh simple changes to it, and we have some pretty useful code, right? So, if we make our boundary bigger, 10 plus or minus one, we're going to get more values that match this criteria, right? So, in fact, we got 40 of them, right? All the way from uh 81 all the way up to 120. They all match the criteria, which is when you take the square root of that value, it's plus or minus uh uh 10 uh nine to 11. Yeah. Any questions about this example? I know it's kind of involved, but I hope that actually drawing a picture helped explain what we were trying to get at. And then at that point, it should have been pretty easy to figure out the structure of the code itself. Any questions? Yes. Question regarding the range. The Why does it have to be uh like that large of a number? Like it could it would be smaller. It could be smaller. Yeah, I mean it we could have done n n n to the power of four. We just couldn't do n squared because then we might miss we well, we would definitely miss 101 and 102 in that particular example. And in fact, if our epsilon is really big, we might actually, I'm not sure about the math, but if our epsilon's really big, we might actually need to go bigger than n cubed as well. I'd have to think about that. But, we just it's okay. I I mean, it's fine to make it big. It doesn't take that much longer to compute cuz the you know, running the function is is very quick to Python anyway. Yeah. Uh yeah, there's a question. Yes, I had a similar question. So, is it a reason why we chose n cubed as like this arbitrary number that's big enough? Yeah, arbitrary number that's big enough. Um what we could have also done, just along those lines, is we could have done a little something a little bit smarter in here, where once we find this a number that actually works, like once we start incrementing our count, we could have some sort of flag that keeps track of as long as we're incrementing the count, right? Keep going, but at some point you know you're going to reach a number that's too big. And at that point, you can just end the function early, right? You can just break out of the loop, and you don't need to keep looking at, you know, uh all the way up to n cubed. So, we could have done something a little bit smarter to make the function just a little faster with flags. Which you can try. So, see if you can have the program stop as soon as you hit 103. Right? See if you can write the program that uses a flag to uh trigger that event, and then when that event is true, just break out of the loop or return immediately or something like that. Other questions? Okay. So, let's zoom out a little bit on functions. We did this a little bit last lecture. Uh this is a function that we actually wrote last lecture. It was sum of odd numbers between A and B. This was essentially our black box, right? Remember that now we're that we're writing functions, we are kind of separating ourselves as some as a programmer who writes a function, right? You basically make this nice modular piece of code that can be reused over and over again. So, we're separating that aspect from somebody who's using a function. So, once there's a function already written for you, you just use it in code, right? Like we use the bisection root here. Right? I know we wrote it, but I I guess technically I wrote it, but here we just kind of used it, right? And we used it to write this nicer, more complex piece of code. And so, this is what we do. We basically create this black box, and once you know the specification or the docstring of the black box, you don't need to know how it's implemented in order to use it. Um but what I wanted to mention is something I mentioned last lecture is the function definition is just creating a function object inside uh inside the memory. And the name of this function object is the name of the function. So, if we're thinking about the the program there is the orange uh box, we have an object that just happens to be a function which has some code associated with it, whose name is sum_odd. And kind of drawing a parallel to that is when we create just a variable as we have been so far, right? Here we're creating an object too, whose name is low. So, in that same way, that black box is basically saying, I am creating a function object that has some code associated with it, whose name is sum_odd. Okay? So, in this case, I've got sum_odd, low, and high as three sort of objects inside my program. And then only when I make a function call does the uh code associated with the function object run. Right? So, up when I'm defining the function, it does not run. It just stays inside computer memory as an object that exists. And when I make my function call is when I use that object. So, the function call basically takes my variables and um and matches them to the function definition. So, A gets matched to low, and B gets matched to high. And low and high in the function call have actual values associated with them, two and seven. And so, that function will then go ahead and do the work, and at the end it's going to return something, either an actual value or none, and then that actual value replaces the entire function call. So, in my program, the variable my_sum here is going to be equal to the return. All right, just a little recap, but hopefully this kind of keeps bringing that point home. So, now we're going to talk about in more detail what exactly happens when we make a function call. So, when we make a function call, you can think of the program as sort of taking a pause. Right? I've got my main program, and in my main program I have a function call. That main program will just pause for a bit. And that function call, you can treat it as sort of a little mini program that needs to run and terminate, return a value, before the main program can resume executing. Okay? So, that little mini program, that function call, basically creates its own little environment that it lives in. Right? So, in that little environment, it can create variables just like we would in a regular program. It can modify variables. It can print things, right? It can do all this work within its body. And at some point, it'll finish its job, finish its task, and it'll have some value that's the result of all of that work that it did. And that value is what it hopefully returns back to the main program, and then the main program can can finish its can finish its its job. Okay? So, what's key here is that every time you make a function call, you basically create a new environment, okay? And that environment is completely separate from the main program environment. As soon as the function call terminates, that uh function call environment disappears. So, any variables that were created within that environment of the function call will also disappear, okay? So, all we're left with is just what's in the main program. So, now we're going to talk a little bit about environments, okay? And if you understand this, you'll understand 80% of of functions and what to do with them. Okay. So, basically, when you first run your program, uh the program enters what we call the global environment, the main program environment. And anytime you make a function call, we're creating this new environment, okay? So, what exactly happens when we create these when we do these function calls? How How do these environments interact? And the answer is they don't actually interfere with each other that much. They only interfere with each other through passing in parameters and through returning values. But beyond that, these two different environments, the main program environment and a function call environment, can actually have variables that have the same name, but don't interfere with each other because they exist in different environments, okay? So, we're going to look at this example uh to so to showcase that. So, here's a function. It's pretty simple. It does not do much. It takes in one parameter, uh probably a number, and adds one to it, right? So, takes in an X and uh does X + 1, reassigns X to it. And then it does this print statement, and then returns the new value of X. So, it added one to whatever you passed into it, and it returns that new value. So, that's the definition. Again, this just sits in Python memory. It doesn't actually get run until we make a function call. The parameters here, when we wrote our function, are called formal parameters because there's no actual value associated with them, right? We're writing this function assuming that at some point we're going to get a value for X. But at the time we're writing the function, there's no value for X. It's just this abstract variable. Okay? And we're using that variable X within the function body assuming that at some point we're going to get an initial value for X, right? So, X is equal to three, and then it would at which point the body can then execute. Now, when you make a function call in the main program scope, that's when you uh pass make a function call with the with an actual parameter. So, here you'll notice I'm using the same name X, but this X inside the main program is different than the X that's this formal parameter of the function. This actual parameter, when we make the function call, is mapped to the formal parameter. So, at that point the formal parameter can get the value of the function call, which is three. Okay? And in fact, it doesn't actually matter what we name this variable out here, right? We can name X is equal to three and make the function call f of of X, but we can also have Y is equal to three and we make the exact same function call f of Y, right? Because we want to pass in three as a parameter to this function call. Okay. So, this X out here is different than this X over here. So, the Oh, yeah, go ahead. The formal is the one from the function definition. We say it's formal cuz there's no value associated with it when you first write the function. Right? You write the function first, there's nothing going on here. And then you have some code that actually now is taking on some values and you can run it. Yeah. So, let's trace through this code little by little to see exactly what environments get created as we make function calls. So, again, this is my black box. It's a function. Uh when I first run the program, we finished the function definition, so we're at this point in our program, right? Before we do X is equal to three. Inside my sort of computer Python memory, what I have is one environment created, and that's the environment of the main program. The only thing I have in this environment is my f. Right? Because at this point in the program where the red uh arrow is, I just had a function definition. So, again, it's a definition. It's it's a function whose name is f, and it's an object, right? I it's not being run quite yet. It's an object that contains some code. Now, we have X is equal to three, so that's pretty easy. Inside my main program environment, I've got a variable named X, whose value is three. And then I have my function call. So, as soon as Python sees a function call, it creates a new environment. And the current environment where the call is being made from, so the main program one, will be put on hold. Okay? So, here I'm calling function f. So, now I'm creating this new environment that think of it like this mini program, this little task that needs to get done before the main program can continue executing. So, I need to figure out what's going on in this mini program, right? In this function call to f. All right, so here's my new environment, the scope of f. The first thing that we need to do is figure out what are the parameters of f. So, we look at the function definition, and we see it has one parameter named X. So, we're going to take that X and the first thing we're going to do is map the formal parameter to the actual parameter. Okay? So, we're going to make the formal parameter of F named X take on the value three. Okay. That's kind of what we've been doing already, but now this is getting down to sort of details. Just details. We've mapped all the parameters. The body of the function executes. I've again kind of blurred out this one cuz we're not in this global scope. We're trying to figure out what F is doing. So, the body of F says take X, add one to it, and reassign it to X. So, what's X inside my function? It's three. We add one to it and we make X before. Uh I skipped one thing, which is if in my main program I had Y is equal to three and F of Y, nothing really would have changed. Right? My formal parameter of F is still X and I'm still mapping X to the value that's uh in my uh here in the actual parameter. Okay, so in my scope of F, I've got X is three. I increment it by one. It gives me four and I resave it back into X. And again, there's no collusion there's no collusion here, right? In terms of naming because the scope of F, the environment at F has a variable named X and I'm just doing stuff with the X that F knows. I do have another X inside my global scope, but that one's put on hold for now. Okay. All right, so I've done X equals X plus one. Then I do the print statement. So, in F of X, X equals four, that gets printed out, and then I return X. So, the thing that gets returned is the value of X, so four. And this again replaces the function call. So, this gets returned back to whoever called me. And the environment that called me was just my main program. And here I'm going to return four and this is going to replace that with four. As soon as the function sees the return and returns that value back, it goes away. So, notice that X that we had created is gone. Now we're in the main program. There's no there's no confusion, right? My main program has its own X. That other X that was part of the execution of F is gone because that function finished its job and it doesn't need its environment anymore. So, now the return of the function replaces F of X and we see Z is equal to four. Okay, that was super detailed. Um but that's kind of what happens step-by-step when we make a function call with the new environments being created. So, if you can understand that, it should be uh it should be pretty straightforward to not, you know, and you won't get confused when you see an X out here, you have F of X, you know, as one function and then maybe another function that has G of X um and so on. Okay. So, in order to know the scope that you're in, the environment that you're in, you need to know what expression you're evaluating, right? So, here we were evaluating this function call. So, that means that we were inside the environment of F. Another example, and this one's a little bit weird. It shows some of the nuances of Python. Um and these aren't necessarily true in other languages. So, I'm just going to do the drawing of the scopes out here. So, let's start with the one on the left. So, you can see here I've got one function F of Y and I've got the main program that creates X is equal to five and then a call to Y. So, inside my main program, I've got X is equal to five. And then I have a function call to F. Function call means we need to create a new scope. So, this one's put on hold for now until we figure out what F {parentheses} X is right here. Okay. So, the first thing we need to do is grab F and take all the formal parameters of F. There's one. Its name is Y. And map them to the actual parameters. So, I'm calling F with five. So, I'm going to map Y to five. This function is going to take uh uh now do its the body of its function. X is equal to one, so it creates also an X whose value is one just within its scope. It adds one to X, so this becomes two. And then it prints X, so it's going to print two. And then the function terminates. It returns none, right? There's no return statement. And it the function is done. So, this line has now finished. And the last thing that the function does after it's done the return is the scope goes away. And the last thing we need to do now is print X. So, this will print the value of X in the global scope, which is five. So, the output of this a little piece of code on the left side here is two and five. Okay. What about the middle code? Similarly, I've got a function definition and then I create X is equal to five. And then I make a call to G. Right? X is five, so as soon as I see a function call, I need to create a new scope. And I need to map all the formal parameters of G. It has one formal parameter. Its name is Y. That one will be mapped to whatever I made the function call with. Five, right? X is five out here. So, that gets mapped to five. What is this function going to do? Well, it prints X. What's X inside the scope of G? Do I have a G inside uh an X inside G? No. So, this is something that Python does. It says, "Well, if your environment doesn't have a variable named X in this case, look further out and see who called you." Well, which environment called this G? The main one, right? Does your bigger environment, the one who called you, have a variable named X? It does, right? It's five. So, Python grabs the value associated with that larger environment. And if that larger environment didn't have one, it would look further out and further out out until it doesn't have an environment to look at. So, G is going to print the value of X, which is five. And then it's going to print X plus one, which is six. And then it's done. It returns none. And then as soon as it returns none, this scope goes away. And all we're left with is the global program. And we print X, which is still five. What I want you to notice is that that function G printed X plus one, but never modified X. Right? We never said, you know, something like X is equal to X plus one or something like that. We just figured out what X plus one was and printed it. Okay. All right, one more example and this one will actually end up in an error. So, here I've got X is equal to five just like before. And then I have a function call to H. So, again a function call means a new scope is created. I've got one variable Y. That's my formal parameter. It gets mapped to whatever I called the function with, five. Oops, S. Um and then what is this function doing? That line X plus equals one is X is equal to X plus one. This is actually an error. Python doesn't let you do that. And the error it gives you is actually what it says there. So, unbound local error. Local variable X is referenced before an assignment. So, it doesn't actually grab the value from the outer scope like we did in the middle bit. It doesn't grab it because it thinks you're trying to create a variable named X inside H and you're trying to add one to X. But you never had a line that said X is equal to something originally inside H. Okay? And so, when you're trying to say X is equal to X plus one, it's trying to look for an X inside the scope of H, but it doesn't have one. And so, that's where we get that error from. And this is not some I mean it's it's just a nuance of Python, but it's kind of important to understand that you can access variables, but you can't change variables outside of your scope. Okay, so the middle one just accesses a variable, adds one to it, and prints it. But we never said X is equal to this value. Okay? And it's kind of like, I guess, the error you get is kind of like if you made this be something completely different like Z. You would get the same error. You know, it would be error uh variable Z uh referenced before assignment, right? So, like you can grab X plus one, but I don't know what Z is. Or something. That should be Z. So, did you say like um like inside the definition like z equals x and then do like x plus equals one cuz if you're looking at your cross side and like So if you know because if you want to if you want to explicitly say that you're taking it from outside there's a keyword called global that you'd need to write that explicitly says hey I'm grabbing this value variable that is not part of me it's part of the it's in the you know the the main program the global scope. Okay the last thing I want to talk about is using functions as arguments to other functions so Um The way I've sort of been explaining a function definition is basically saying that when we define a function python essentially puts some code in memory whose name is the function name Right so basically the function name creates for me an object inside memory that happens to be a function object. And just to show you sort of what that means is we have a function is even right we've definitely created it if we say the type of is even It's function right so the function is even Actually has a type and its type is a function in python. So functions are basically just objects just like an integer is an object a boolean is an object a float is an object right a function it it's an object it just looks different it has a bunch of code associated with it. So if a function is an object what that means is we can use an assignment operator on a function name. So we can have two names that of functions that point to the same function code We can use a function as an argument to another function like a parameter to a function or we can return a function from another function. Okay. So here's an example Pretend that this is our code file we've got the memory The first line of code here the definition basically creates this function object for me in memory. It's kind of like a variable right is underscore even is the name of this function object and this variable is bound to my function object with some code associated with it right so you think of the function as just an object. Similarly right when we write r is equal to two I think of that as the same thing right r is the name and I've got an integer object whose value is two. That's exactly what happens when we create a function definition. Right. Similarly pi is is equal to 22 over seven right pi is the name associated with a float object that's has that value. So what we can do right now that we've established that a function is basically an object with a name we can say a line like this my funk equals to is even. The right hand side here Is just the name of my function. It's not a function call right notice there's no parentheses after is even there's no parameter none of that it's literally the name of my function. So inside memory what I've ended up doing is I have two oops I have two names My funk and is even that both point to the exact same function object. So that means that that function object so this is even function Can be referenced by both of these names. So on the next two lines here a equals this and b equals this I'm running the same code just referenced by different names. Right so then a is going to be bound to false and b is bound to true because I'm I'm accessing the same code fundamentally By different names. Does that make sense? Yes awesome. So everything in python is an object including functions it's strange to think but there you have it. So let's look at this code. I've got three function definitions and only one function call. What are the functions function definitions? One I have named calc it takes in three parameters one I have add it takes in two parameters and one I have div it takes in two parameters. Add Does something pretty simple div has maybe a print statement but also does something pretty simple. Calc is the one that's really strange right? Because it takes in these three parameters but what's the thing it's doing in here it's kind of treating one of the parameters Op Operation As a function. Okay. That's what's strange about calc so now let's trace through the code to see exactly what that means for us. So when I first run my program I have Three function definitions so I'm creating three function objects inside memory calc a function object that has some code Add a function object that has some code and div a function object that has some code. And then we get to the good stuff res equals the function call. So res is going to be a variable that's going to have a value What value? We need to figure that out. Calc Is a function call. Every time we have a function call we need to create A new environment so now we are creating our calc environment. So we've put aside the main program scope for now and we're focusing on what calc is going to do. First thing we need to do is take every single one of our parameters and map it to the actual parameters right? So the first parameter is op It gets mapped to Add. The next parameter is x gets mapped to two the last parameter is y gets mapped to three is everyone okay so far? Yes okay I've literally just matched names a formal parameter to actual parameter. Okay so now we finished mapping the form the parameters next we get to run the body of the function return What is this? Let's replace op x and y with the actual values. This basically becomes return a function call add two comma three. I've just replaced the names that's it. What's add two comma three? It's another function call right? So calc is going to have to be put on hold because I have to figure out what add is going to return. Okay. So what's add going to return for me? Well add two comma three is what I'm trying to figure out so I'm going to map a to two b to three It's going to do five as the return So returns five to whoever called it and whoever called it was calc right here. So this expression here op x comma y which was add two comma three Is replaced with five. Everyone okay so far? Awesome. Okay and then calc can now finish right notice add finished its job so it went away now calc can finally return its value so it can finish as well so this one will return five To whoever called it which was the main program And finally calc has finished its job and it returned five. So step by step we just kind of traced through the code you know Functions out to in and replacing variables wherever needed. So it's your turn. Tell me what's the value of res given this function call to calc and what's going to get printed? So we can even write our functions So in the main program What do I have? Yep calc and div are my functions. That's it. Which one? Yep res will be the the result yep and the res we will have a question mark cuz we don't know what it is yet. And what's the first thing I need to do? Yeah make a new scope exactly. So that's the scope of calc and we're going to map op To div What do we have x and y To two and zero thank you. So what's op going to do? Yes exactly we make another scope for div. A Is two and b is zero. So we're kind of two scopes deep. What's div going to do? Yep so div prints out the thing denom was zero And what's div returning? None perfect so div returns none here To calc And then div is gone. And then none gets returned from from calc here. And then calc is gone. And all I'm left with is res equals None. Exactly, the return of calc. One more example uh showing scope. Um just kind of showcasing these uh sort of the same idea. So, I've got three functions here. Func A, Func B and Func C. Func A takes in, you can see, no parameters. Func B takes in one parameter. Func C takes in two parameters. And if we scan the code, we see that one of them is weirdly doing something. So, it's actually going to be a function, right? Cuz you see we're calling it like a function inside here. So, we know F is going to have to be a function. So, if we run this program, first three function definitions basically put some code for us in the memory. When we make uh func call, uh sorry, Func A call, this creates a new scope. A has no parameter or Func A has no parameter, so there's nothing to bind. All this function's going to do is print inside Func A and then return none. Right? So, that whole thing is going to print none. Next, Func B is going to uh be another function call right here. So, it creates a function scope right here. We map the formal parameter Y to two. And then we finished mapping all the parameters. And what we need to do next is do the body. So, we print inside Func B and it just returns the value you passed into it. So, not a very smart or interesting function. So, it prints that and returns two back to whoever called it. Whoever called it was here. So, this print statement becomes print 5 + 2. The return. So, that's going to print stuff into the console. And lastly, the interesting one is going to be Func C. So, Func C, notice I'm calling it with an actual function I have in hand, Func B, right? One of these that I've defined here. So, Func C is a function call, so there's my scope. I am mapping formal parameter F to Func B and Z to three. So, just mapping one one by one. And then I'm doing the body of Func C. So, the body says now print this and return this. So, we print the statement. And then the return basically says, well, what's F function call FZ? We have to figure out what the actual values are. And it's Func B {parentheses} three. So, that's another function call, which means another function scope. Again, not a very smart or interesting function, this Func B. It just takes in the three. It prints inside Func B and it returns the three back to whoever called it. So, that func that function is done. And then the Func C can terminate and return three to whoever called it, which was out here. And notice as soon as a function call terminates and does a return, it immediately it, you know, all of its variables, everything that got created inside in that environment uh go away. They get wiped out. Okay. Give you about a minute to try this. So, write a function that meets the following specifications. So, I have a function named apply. Criteria is a formal parameter, right? So, at some point you're going to have a function that does this. It takes an integer a number, an integer, and returns a boolean. Right? So, however a function does that, that's what's going to be passed in. And then N is an integer. And what I want you to do is tell me how many numbers from zero to N match that criteria. So, when I apply the function criteria to numbers zero through N, how many of those actually return true on that function? So, just to show you something uh you know, what this means concretely, here's my function apply. Here's a function that I could call the apply with, is even. Sorry, I lied. I guess we are seeing is even a few more times in this lecture. Um so, here's a function is even. And basically, I run apply by saying I want to run function apply with the name is even. Right? So, here I am mapping name to numbers zero through 10. So, I'll give you about a minute to try it out and then I can write it just so we have some uh so we finish on time. Does anyone have a start? So, we know we want to touch each number zero through through N to see whether this criteria applies to them, right? So, what's the start to get that going? Yeah. For I in range N plus one, cuz we want to include N. How do we apply the function criteria to each one of these values? Yeah, exactly. We just say criteria. And this name will be replaced with whatever function we're going to call apply with, I. Right? And this criteria I will basically be the return of criteria. What did I say criteria returns? It takes in a number and returns a boolean. So, we know that this is a boolean. What do I want to do with this boolean? If it's true, I want to count it. If it's not, I don't. So, if criteria I count plus equals one. Right? Let's put this up here. And let's remember to uh initialize our count. And then that's it, right? If it's if it doesn't match, then I don't care about doing anything with it. So, then we just return count. So, notice I'm using my function here that's just a parameter, kind of like a placeholder for any other function. So, this is even function when it's a parameter to apply will tell me six, right? 0 2 4 6 8 10. That's That's six values that match this criteria. And what's cool is that I can actually create any function. So, if I want a function that's called is five, for example, right? It takes in a number and returns true if that number is equal to five. Right? It's still a function that takes in an integer and returns a boolean. All I need to do then is run this apply with the function is five. Right? So, I just changed that here. And then if I run it, it should just give me one value, right? The five, of course, is one that matches this is five criteria between zero and 10. Yeah, so that's basically it. So, we saw some uh uh function a lot more you can do with functions. They're basically objects in Python. So, they can be manipulated just like you would any other object. You can have them be parameters to a function. You can have them be returned from a function. Uh you can assign another name to this function body. Things like that. Uh I showed you what to how to think about environments, right? So, that the naming doesn't get confusing, right? As soon as a function call is made, that means another environment is created. So, variables created within that environment have no influence on other variables created in other environments, okay? Um and functions are very nice a very nice way for us to write code that can be easily be be built upon. That's it. Thank you. Thank you.
Original Description
MIT 6.100L Introduction to CS and Programming using Python, Fall 2022
Instructor: Ana Bell
View the complete course: https://ocw.mit.edu/courses/6-100l-introduction-to-cs-and-programming-using-python-fall-2022/
YouTube Playlist: https://www.youtube.com/playlist?list=PLUl4u3cNGP62A-ynp6v6-LGBCzeH3VAQB
This lecture further explores functions and their scopes and environments as well as functions as objects. Functions are first-class objects that have a type and can be assigned as a value, used as an argument for another procedure, or returned from another procedure. Being careful about environments enables the creation of concise, easily read code.
License: Creative Commons BY-NC-SA
More information at https://ocw.mit.edu/terms
More courses at https://ocw.mit.edu
Support OCW at http://ow.ly/a1If50zVRlQ
We encourage constructive comments and discussion on OCW’s YouTube and other social media channels. Personal attacks, hate speech, trolling, and inappropriate comments are not allowed and may be removed. More details at https://ocw.mit.edu/comments.
Playlist
Uploads from MIT OpenCourseWare · MIT OpenCourseWare · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
21. Post Trade Clearing, Settlement & Processing
MIT OpenCourseWare
10. Financial System Challenges & Opportunities
MIT OpenCourseWare
7. Technical Challenges
MIT OpenCourseWare
3. Blockchain Basics & Cryptography
MIT OpenCourseWare
19. Primary Markets, ICOs & Venture Capital, Part 1
MIT OpenCourseWare
1. Introduction for 15.S12 Blockchain and Money, Fall 2018
MIT OpenCourseWare
Chalk Radio, A Podcast about Inspired Teaching at MIT (Teaser)
MIT OpenCourseWare
Nuclear Gets Personal with Prof. Michael Short (S1:E1)
MIT OpenCourseWare
How Africa Has Been Made to Mean with Prof. Amah Edoh (S1:E2)
MIT OpenCourseWare
Making Deep Learning Human with Prof. Gilbert Strang (S1:E3)
MIT OpenCourseWare
Social Impact at Scale, One Project at a Time with Dr. Anjali Sastry (S1:E4)
MIT OpenCourseWare
Film is for Everyone with Prof. David Thorburn (S1:E5)
MIT OpenCourseWare
Lecture 12: Aircraft Performance
MIT OpenCourseWare
Lecture 3: Learning to Fly
MIT OpenCourseWare
Lecture 13: Interpreting Weather Data
MIT OpenCourseWare
Lecture 21: Weather Minimums and Final Tips
MIT OpenCourseWare
Hand-on, Minds On with Dr. Christopher Terman (S1:E6)
MIT OpenCourseWare
Part 4: Eigenvalues and Eigenvectors
MIT OpenCourseWare
Part 5: Singular Values and Singular Vectors
MIT OpenCourseWare
Part 3: Orthogonal Vectors
MIT OpenCourseWare
Part 2: The Big Picture of Linear Algebra
MIT OpenCourseWare
Part 1: The Column Space of a Matrix
MIT OpenCourseWare
Intro: A New Way to Start Linear Algebra
MIT OpenCourseWare
9. Chromatin Remodeling and Splicing
MIT OpenCourseWare
28. Visualizing Life - Fluorescent Proteins
MIT OpenCourseWare
20. Roth's theorem III: polynomial method and arithmetic regularity
MIT OpenCourseWare
8. Szemerédi's graph regularity lemma III: further applications
MIT OpenCourseWare
19. Roth's theorem II: Fourier analytic proof in the integers
MIT OpenCourseWare
12. Pseudorandom graphs II: second eigenvalue
MIT OpenCourseWare
1. A bridge between graph theory and additive combinatorics
MIT OpenCourseWare
Special Episode: Teaching Remotely During Covid-19 with Prof. Justin Reich
MIT OpenCourseWare
Spring 2020 Update from Dean Rajagopal
MIT OpenCourseWare
S1E7: Unpacking Misconceptions about Language & Identities with Prof. Michel DeGraff
MIT OpenCourseWare
Climate 101 Live
MIT OpenCourseWare
Welcome for Volunteers (for EarthDNA's Climate 101)
MIT OpenCourseWare
Learning to Fly with Drs. Philip Greenspun & Tina Srivastava (S1:E8)
MIT OpenCourseWare
Thinking Like an Economist with Prof. Jonathan Gruber (S1:E9)
MIT OpenCourseWare
2. Cyber Network Data Processing; AI Data Architecture
MIT OpenCourseWare
1. Artificial Intelligence and Machine Learning
MIT OpenCourseWare
2: Resistor Capacitor Circuit and Nernst Potential - Intro to Neural Computation
MIT OpenCourseWare
14: Rate Models and Perceptrons - Intro to Neural Computation
MIT OpenCourseWare
4: Hodgkin-Huxley Model Part 1 - Intro to Neural Computation
MIT OpenCourseWare
18: Recurrent Networks - Intro to Neural Computation
MIT OpenCourseWare
3: Resistor Capacitor Neuron Model - Intro to Neural Computation
MIT OpenCourseWare
15: Matrix Operations - Intro to Neural Computation
MIT OpenCourseWare
13: Spectral Analysis Part 3 - Intro to Neural Computation
MIT OpenCourseWare
16: Basis Sets - Intro to Neural Computation
MIT OpenCourseWare
20: Hopfield Networks - Intro to Neural Computation
MIT OpenCourseWare
8: Spike Trains - Intro to Neural Computation
MIT OpenCourseWare
7: Synapses - Intro to Neural Computation
MIT OpenCourseWare
19: Neural Integrators - Intro to Neural Computation
MIT OpenCourseWare
5: Hodgkin-Huxley Model Part 2 - Intro to Neural Computation
MIT OpenCourseWare
6: Dendrites - Intro to Neural Computation
MIT OpenCourseWare
17: Principal Components Analysis_ - Intro to Neural Computation
MIT OpenCourseWare
12: Spectral Analysis Part 2 - Intro to Neural Computation
MIT OpenCourseWare
11: Spectral Analysis Part 1 - Intro to Neural Computation
MIT OpenCourseWare
9: Receptive Fields - Intro to Neural Computation
MIT OpenCourseWare
10: Time Series - Intro to Neural Computation
MIT OpenCourseWare
1: Course Overview and Ionic Currents - Intro to Neural Computation
MIT OpenCourseWare
The Power of OER with Profs. Mary Rowe and Elizabeth Siler (S1:E10)
MIT OpenCourseWare
More on: Algorithm Basics
View skill →Related Reads
📰
📰
📰
📰
Blind 75 | Arrays & Hashing — 04 Group Anagrams
Medium · AI
Finding the Longest Increasing Path in a Matrix: From a Simple DFS Idea to an Optimized Solution
Medium · Python
LeetCode 24: Swap Nodes in Pairs
Medium · Python
What I learned writing 1,096 tests for algorithm animations
Dev.to · Nav
🎓
Tutor Explanation
DeepCamp AI