Practical Guide to Python Functions, Arguments & Scope
Transcript from the "Functions, Arguments & Scope" Lesson
>> Functions in Python are defined with that def keyword that we saw earlier, followed by a function name which is lower case, separated with underscores. And then parenthesis that contain zero or more arguments, and a colon. Everything that is indented after the function belongs to that function. So early on in the class, if you remember we tried to from future import braces, and we got a no way error, never gonna happen, that was a little Easter egg.
[00:01:02] Because if things are not indented at the correct level, you're going to get syntax errors. If we try to create functions that are missing some of those core components, so if I try to create a function. That does not have that colon, I'm going to get an invalid syntax.
[00:01:28] So def, the name of the function, parentheses, colon, and we'll see the repo shows us a helpful hint. Once we have that colon, it's going to turn into dot, dot prompt to say, hey, I'm expecting more input here. In the repo, you can just hit Tab. When I hit Enter again, the repo is gonna say, hey, I'm still waiting for more input.
[00:01:57] If you're done defining your function at this point, you can just hit Enter again to get back to that three arrow prompt that we saw earlier. And that means that the function has now been defined, and it means that I can call it. When we are writing Python files, this extra new line after the function, if you don't have it, it's not a syntax error.
[00:02:24] But prep it, it does state that you should have a new line after your function definitions just for readability sake. You can save the output of calling a function into a variable, I would have to change my function a little bit. So I would have to change my function to actually return something.
[00:02:49] Because if I see what isn't greeting right now, it's actually gonna be a no value. The function only printed something, it does not return any values. So, I can redefine my function, And have it return a value instead of printing it. Now when I call my function, it should return the string Hi, and now I can save that to a variable.
[00:03:26] So return statements allow you to do stuff in the function and then pass those values back to the color. You can return whatever you like. If you're going to be returning more than one value, you can use a tubule. Now, pretty straightforward calling functions with no arguments, how do we start making functions that do accept arguments?
[00:04:00] We define what arguments we want to accept by separating the names that we expect them to be with commas in the parentheses. And then we can use them in our function. If we wanted to store the value of this, that would be pretty straightforward. Now result is an integer with 30.
[00:04:42] We can also have optional arguments and provide a default value for them. Invalid syntax, I forgot to say def. You would not want to write a function like this in production, your coworkers would be mad at you. It is a mystery function that does some weird stuff, but just for the sake of example.
[00:05:18] Now I can still add my numbers, let's say 3 and 5. I'm actually gonna get 9, because there's this default value in z that is 1, but I can also pass in my own value for it. These arguments must be provided because they don't have defaults providing these arguments is optional, and they need to be in this specific order.
[00:05:49] Required arguments need to be defined first, optional arguments need to be defined last. If you mix up the order of these, you're going to get errors. And it's pretty helpful error, it says syntax error, non default argument follows default arguments. One more thing about functions is that here we define them exactly as they were defined in the function.
[00:06:29] If you provided labels for these when you call the function, you can pass those in any order you would like. So looking at the add numbers function here, I could call add_numbers(1, 2, 3) or I could say that y = 1, z = 2, and x = 3.
[00:07:00] And because I've helped Python out and told it, hey, I'm not calling these an order, but I am giving you the labels, it's able to figure out what your intent was. Does that make sense? Okay, cool. Now. We talked about default argument, we talked about order. If we try to call a function without all of its default arguments, we're going to get an exception.
[00:07:40] So for add numbers, I have two arguments that need to have values x and y. If I tried to call this function with only one value, I'm going to get a pretty helpful error, it's a type error. It says add numbers is missing, one required positional argument of y.
[00:08:01] Right, because I passed in a value for this, but not for this, and Python doesn't have a default value for it, it doesn't know what to do If you have arguments that have default values for everything, you can then pass in none of them, or some of them, or all of them, you can mix and match.
[00:09:51] Don't use mutable types as default arguments, they don't behave the way that you expect. So if I have a function, And I wanna have a default argument with a list. And say, Append this string to my list when I call it. When I call this function the first time.
[00:10:33] Oops, Sorry, I want to go ahead and return that. So that we can actually see what happens. When I call it for the first time, It does the right thing. When I call it the second time, there is now two instances of stuff in this list, and then three, and then four.
[00:11:00] Do not use mutable arguments for defaults, because the way that Python works under the hood is these get declared once. So when you do this, you are going to continue using that very same instance of my list every time you call that function, even though that is not what you intended to do.
[00:11:25] So, this is the source of a lot of subtle bugs for beginners. So remember, no mutable default arguments. The way that you would want to do this instead is to have a, Have a placeholder here where you're using a nun value as a placeholder. And I'm gonna introduce some concepts we haven't talked about yet, but then you can just say If I've passed in a list, then use it.
[00:12:03] Otherwise, you can say, if not my list, which means if it's sorry, you wanna say, if my list is equal to none, Then making new list here, and then append to it. Now, when I call do_stuff(), it's going to do the right thing each time because I took care of creating the list in this function, I did not pass in an empty list as a keyword argument.
>> It only appends stuff in the case where my list isn't defined.
>> Yeah, just a silly little example. So right, I would want to move this over one to the left so that this example worked when I did pass in a list to start with. Good catch, thank you.
[00:13:16] Cool, so these are arguments. And I wanna talk about scope a little bit. There is scope inside of a function. So I'm going to exit my repo and start it from scratch to clear out everything that I might have defined already. If I have a function that takes a name and prints it.
[00:13:55] I cannot access this name variable outside of the function, outside of this indented zone, because the name is only defined inside of the function. Once the function exits, that variable doesn't exist. So, Python scope works pretty similar to scope and other languages. This is something you want to be mindful of.
[00:14:22] You want to be very careful when you're using variables inside of a function that are defined outside of it. Because if you try to change the value of that variable inside of the function, the value is only going to apply for that scope. When your function exits, you're not actually going to be able to modify the value of the variable defined outside of the function.
[00:14:55] This can result in some weird subtle bugs. So here's an example. And I can say print, Out the name outside of the function. And then I'm gonna make a method that says try to change the name And I'm gonna say that name in the function is Max. And print out.
[00:15:32] Name inside of the function. Now if I call this method try change name, the name inside of the function is Max, but the name outside of the function is still Nina. So don't try to change variables in a function that were declared outside of it. You will have access to them, which can be helpful if you have like a global variable defined, that is like a URL or something that's static, that's not going to change.
[00:16:23] But don't try to update it, you're gonna end up with some weird scoping issues. And so a use case for using a variable in a function that's defined outside of it is a constant, and to delineate that it's a constant. In that case, you can name it with all uppercase characters, split with a underscore.
[00:16:52] And that's just convention, it doesn't mean that there's anything different about that variable. It's just named a little bit differently in order to signify something to the readers of the program.