Today we’ll be talking about passing arguments to functions in Python. In particular we’ll be talking about argument types and argument-matching modes.
Well, maybe not the kind of arguments as in the picture.
Table of Contents
Positional Arguments
Arguments are passed by assignment in Python. The objects passed as arguments are assigned to the names used as parameters in the function definition.
Here’s a very basic example:
def func(a, b):
return a + b
x = func(5, 10)
Here the two integer objects passed as arguments, 5 and 10, are assigned to the two names used as parameters in the function definition, a and b respectively.
So, this is how we pass arguments to a function in the most basic scenario. We call such arguments positional arguments because they are assigned to the parameter names by position: the first argument is assigned to the first parameter, the second argument is assigned to the second parameter, and so on.
If there are lots of parameters in a function definition, it’s easy to lose track of them and omit one or more arguments in the function call, which leads to wrong assignments and errors. Besides, sometimes we don’t know how many arguments will be needed. Suppose we want to make a function that can take any number of numeric parameters and calculate the average of them. With just positional arguments it would be impossible. Fortunately, there are a couple of other argument types and argument-matching modes in Python. Let’s have a look at them now.
Argument Types in Python
Here’s a short overview before we dive deeper into the details. We have the following argument types at our disposal:
– positional arguments – matched from left to right
– keyword arguments – matched by name
– default arguments – assigned default values if omitted in function call
– * arguments – iterables unpacked into individual positional arguments
– ** arguments – dictionaries unpacked into individual keyword arguments
And now let’s discuss them one by one. We already discussed the positional arguments, so let’s now have a look at keyword arguments:
Keyword arguments:
Keyword arguments are passed by name. They can be passed in any order. Here’s an example:
def func(name, age, city):
print(f"{name}, aged {age}, lives in {city}.")
We can now pass the arguments in the following order:
func(name = "Jack", age = 38, city = "Sacramento")
or in a different order:
func(age = 38, name = "Jack", city = "Sacramento")
or in a yet different order:
func(city = "Sacramento", age = 38, name = "Jack")
So, as long as we pass the arguments by name, the order doesn’t matter.
There may be also both positional and keyword arguments in a function call. Then we have to pass all the positional arguments first, in the same order as the parameters in the function definition, and then we can pass the keyword arguments in any order. Here’s an example:
def func(a, b, c, d, e):
return (a + b + c + d) * e
x = func(2, 4, e = 6, c = 3, d = 1)
Here the first two arguments are passed by position. The other three are passed by name.
Default arguments:
Then we have default arguments. These are arguments that are optional in the function call. If we pass them to the function, they work as any other arguments. If we don’t pass them, they take default values specified in the function definition.
Here’s an example:
>>> def func(a, b = 10, c = 3):
... return a + b + c
...
The first parameter wasn’t assigned a default value in the function definition, so it’s a mandatory parameter and we must pass at least one argument to the function that will be assigned to it. If we pass just one argument, b and c will be used with their default values of 10 and 3 respectively:
>>> func(5)
18
Now, if we pass 2 arguments, then the second one will overwrite the default value of b and the value of c will be still the default value of 3.
>>> func(5, 4)
12
What about passing all three arguments? Then the default values of b and c will be overwritten.
>>> func(5, 4, 6)
15
With both positional and optional parameters in the function definition, the positional ones must come first, just like in the example we just saw.
If we have multiple optional parameters, we can use default arguments as positional or keyword arguments. Here’s an example with default positional arguments:
>>> def func(a, b, c = 1, d = 2, e = 3, f = 4, g = 5):
... return a + b + c + d + e + f + g
...
The two first arguments are mandatory, but all the rest have default values:
>>> func(10, 10)
35
Suppose we want to use all the default values except the last one: we want to pass 20 as the last argument. Unfortunately, with positional arguments we would still have to pass all the default values of all the arguments that precede the argument for which we want to deliver a different value:
>>> func(10, 10, 1, 2, 3, 4, 20)
50
But we can easily get around this using keyword arguments like this:
>>> func(10, 10, g = 20)
50
Now we can skip all the arguments for which we want to maintain the default values.
* arguments
Then we have the * arguments.
The star notation can be used either in the function definition or in the function call.
We use the star notation in a function definition if we want our function to be able to take an arbitrary number of positional arguments. All the arguments will be packed in a tuple. Here’s an example:
>>> def func(*args):
... for arg in args:
... print(f"=> {arg}")
...
We can now call the function with any number of arguments, including zero:
>>> func()
Let’s pass one argument:
>>> func("one")
=> one
Let’s pass 5 arguments:
>>> func("one", "two", "three", "four", "five")
=> one
=> two
=> three
=> four
=> five
We use the star notation in a function call to unpack positional arguments. Here’s an example:
>>> def func(a, b, c, d, e):
... return a * b * c * (d + e)
...
Here we have a list of numbers:
>>> nums_list = [5, 4, 3, 2, 1]
We can unpack the list into the 5 individual arguments required by the function:
>>> func(*nums_list)
180
We can do the same with a tuple:
>>> nums_tuple = (5, 4, 3, 2, 1)
>>> func(*nums_tuple)
180
** arguments
Finally we have the ** arguments. They work just like the * arguments, but for keyword arguments. So, again, if we use the ** notation in the function definition, we can pass an arbitrary number of keyword arguments, which will be packed in a dictionary. Have a look:
>>> def func(**kwargs):
... for kwarg in kwargs:
... print(f"{kwarg} => {kwargs[kwarg]}")
...
Now we can pass any number of keyword arguments, including zero:
>>> func()
Let’s pass one keyword argument:
>>> func(name = "Alice")
name => Alice
And now let’s pass 5:
>>> func(name = "Alice", age = 74, city = "Rome", hobby = "knitting", pet = "rat")
name => Alice
age => 74
city => Rome
hobby => knitting
pet => rat
We use the ** notation in a function call to unpack keyword arguments. Here’s an example:
>>> def func(a, b, c, d):
... print(f"{a} - {b} - {c} - {d}")
...
Here we have a dictionary where the keys are the names of the parameters in the function definition:
>>> french_numerals = {"a": "un", "b": "deux", "c": "trois", "d": "quatre"}
Now we can unpack the dictionary into individual keyword arguments:
>>> func(**french_numerals)
un - deux - trois - quatre
In order not to overcomplicate things I will cut the post here. But I’ll write some more posts on passing arguments to functions soon, so stay tuned!
Here’s the video version of this article:
lol at the begining