 In this video we are going to continue the study of functions. So in this video we want to look into how can we add more than one parameter to a function and how can we pass more than just one argument to a function in a meaningful way. So let's go ahead and create a new file and call it arguments. That's a good term. So let's go ahead and define our function that we, for the example that we used to work with in this course. So again the example is that we are given a list of numbers and we want to find the average of all the even numbers in the list. So let's go ahead and define first of our numbers list as the number 7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1 and 4. So these are the numbers from 1 through 12 in no particular order. So let's also briefly recap of how we define a function. So we do that with a dev statement and we are going to call the function as before average evens and for now the function will also only take one parameter as its input and we call it numbers just as before. Let's also quickly remind ourselves that we always want to write a good doc string. So calculate the average of all even numbers in a list. Let's specify the arguments that we path into the function. So it's numbers and it's supposed to be a list of integers, the whole numbers to be averaged and then the function finally returns the average which happens to be a floating point number. Now let's remind ourselves of how we solved the problem in our second solution approach. What we first did is we created a new list that contained only the even numbers. So let's do that. We are going to write a list comprehension and we're going to write n for n in numbers. If n divided, modulo divided by 2 has a rest of 0. That means we only keep all the numbers if they are even and we assign this new list to a local variable called evens. So in a previous video we learned about the scoping rules and we learned that the variable evens only exists inside a function as it is being executed. And then in the second line we're going ahead and we're going to write average will be set to the sum of the evens divided by the length of the evens, the number of the even numbers. And then we must not forget to also return the average at the end of the function otherwise the function would not give anything back. Let's try it out. So our first test case is we call the function average evens and we pass it our numbers list. It is 7.0 and it is and then also let's make a quick second example. Let's call the function again and let's create a list object on the fly and pass it the numbers 40, 41, 42, 43 and 44 and that should give us an average of 42.0. So let's work with a variant. So the variant goes like this, so let's write it here, variant. The average may be scaled before it is returned. So this looks like a toy example but let's say if we are given a list and we filter out some things we could think of that as a statistical application that eliminates some outliers. And then the averaging is basically just finding a statistic and the scaling that we now introduce for the first time, this could for example be let's assume that the functions are prices in euros and you want to convert them after averaging into dollars and converting from one currency into another would be basically scaling. So that is it looks like a toy example here but really we could easily find business application for that as well. So what do we want to do? So what we need in this function is we need to specify a second parameter that allows us to scale the function. So let's do that. Let's go ahead and add a second parameter here on the parameters list. Let's simply call it scalar and the scalar going to be a float or an integer. So we could view a float as a generalization of integers. That is why I don't have to specify float integer here. And then we say simply multiplies the average. So now that is it and let's now go into the code here and all we have to do to make this work is we go ahead in the last line where it says return average. We will simply add the scalar and we say scalar times average. So before that we have not seen that that we could actually have a full expression here next to the return statement. So far we have only used individual names, variables that are returned but it nothing prevents us from spelling out some expression here. That is not just a variable. So we could do some operation here just like we do with the multiplication. Okay, so let's go ahead and define the new function and by running the cell again this will overwrite the old average events object. Therefore, calling average events is now referring to the new function. However, if we call it now with only one parameter, like here numbers, we are going to get a type error, okay? And that is due to the fact that we are not passing in enough arguments. So we need to pass in one argument for every parameter that we define in the function here. So how could we fix that? Well, one way is to simply pass it a second argument. For example, let's say we want to double the average. So let's simply pass in a two and then we get back 14.0. And if we wanted to do the same here in the second example, then we would get back 84.0, okay? So that works. What is the downside of this? Well, one of the downsides here is that after a while, let's say we write down the function to our code base and then after a while we look at it, we may not know what the two here means by just reading the function call, okay? And then what we would have to do is we would have to go back to the function and into the source code where we define the function and we would have to look up what the second parameter means, okay? So in other words, it would be nice if we could somehow call the function in a different way. And there is, of course, the possibility to do that. So what we could do instead is we could go ahead and call the average events functions, pass it as the first argument, still our numbers list. And as the second argument, we don't just pass in the argument by position, but we specify it by keyword, that is the technical term. So we could also say scalar equals two, and this will also work, okay? So the first two code cells here, they are examples where we pass in all the arguments as so-called positional arguments. So let's maybe quickly write this down. This is called positional arguments. And the second way here, this is kind of a mixed approach. And we have one positional argument and another one, which is called a keyword argument and a keyword argument. And the keyword is just the name of the parameter, scalar, okay? So by saying scalar equals, we say we pass in the argument two by keyword, by the keyword scalar. Of course, what we could also have done is we could also have written numbers equals numbers, okay? So we could pass in both arguments by keyword, that works. And whenever we do that, whenever we pass in all the arguments by keyword, we could actually go ahead and change the order, okay? So Python is smart enough to figure out that the order is different because we give every argument a keyword by which we pass it in. However, one thing we must not do, we must not pass in the first argument by keyword and the second one by position. So in other words, all the positional arguments must come before the keyword arguments, okay? That's just a rule. And then that means let's put it back into the form where we had it before, just like this. Okay, so this is basically the two ways of how we can pass an argument to a function either by keyword or by position. And my recommendation is sometimes for functions like average events, it is kind of intuitive, kind of natural to expect that the first argument is some sort of list of numbers because otherwise the function just would not make sense by talking by its name. So the first argument, yeah, we could really pass it in by position without any double meaning or without foregoing some of the readability. However, for the second argument, I would really argue that writing the function call like this by specifying the keyword is a lot better because then even in a month from now when we look at this code, at this function call, we know exactly what the two means, okay? We don't have to guess. And that is of course important. Okay, so let's continue here with what else can we do? So sometimes you want the user of the function, so the person that calls the function, you want to force them to use the second way, to use the keyword way. How could you do that? There is in recent versions of Python a nice little syntax. We can simply go ahead and put a star in between the two parameters here. And what that does is any parameter that comes after the star must be passed in by keyword. Okay, that is basically what it does. Other than that, the keyword, the asterisk here or the star symbol does not do anything else really. Okay, in a future video, we will learn what the star symbol here does in addition to that. But for now, let's just keep it simple and say any parameter that comes after the star must pass in by position. And we call them keyword only arguments because they can only be passed in by keywords. Okay, so let's go down here and let's call the function again and this works, right? Because we are using a keyword here. However, if you go back here, then this does not work anymore, okay? Because maybe that's right here, but the second argument must be passed in by keyword. Okay, so that is why we get a type error here because we have to use a keyword now for the second argument. Okay, now you would say that, okay, maybe this is a bit too much because if I, let's say, call the second function, let's say, just for to make a point here, let's say I want to go ahead and I don't want to scale the average, I would have to pass in a one by keyword, otherwise I would get this error. So what else could we do here? Well, what we could do is we could specify a default value and let's make a one here for scalar. And this now means that whenever we don't specify scalar, then it automatically is set to one. And that is often something that you do for parameters that you don't often need to specify, okay? We give it a default value. And then what we could do is we could go down here and we could just leave the one away and now the function works by calling it with only one argument. However, if we want to go ahead and give it a second argument for the scalar parameter, we must not do that by position, we can only do that by keyword. So you now may wonder why would we do that? So what is the advantage of that? And the advantage is that we as the writer of the function, so as the person that defines the function, we can now force the user of the function, the person who calls the function, which often happens to be the same person, right? Oftentimes we are doing both, but we can force the caller of the function to be explicit, okay? And one of the rules in Python, one of the best practices is we better are explicit than implicit. So we oftentimes, when we are in doubt, we often want to spell something out so that later on when in the future, we read our code, it is still explicit and we understand what is going on, okay? So that's the advantage of using this syntax here. Okay, so these are the various ways of how we can go ahead and call a function. So we can specify as many parameters as we want. I would recommend to not go, let's say anywhere beyond five or six, otherwise it is most likely that your function will do too much in just one function. You should keep your function small and simple to understand and that means also don't give them too many parameters and more often than not, a function that you built will have one or two natural, so to say parameters and a couple of them that are not so natural and it basically is a good practice for the not so natural parameters to give a default value and to require a user to use keyword arguments if they want to change the value, so if they want to differ from the default value, okay? So these are a couple of ways of how we can call a function and yeah, so this is it for this video.