When I first started programming in Python this used to trip me up all the time. Hopefully through my pain I have managed to find a way to convey just how simple this concept is.
Working with args
These functions allow you to extend your function massively, as when you design functions, you don’t want to limit the number of inputs to the function to a certain amount. A good example of args in action is when you are are dealing with statistical functions such as sum and mean. If you built a function, which could only add one number to another, then that would not be as useful as adding a number to an unknown range. This is where args come in.
I will demonstrate how args is structured via a simple function and we will deconstruct this function:
Okay so what this does is the following:
- Has two parameters – the first parameter is a normal default parameter that you would expect from a function and the second is prefixed with a (*) asterisk symbol, this denotes that you want to passed unnamed arguments to the function
- The print statement uses an fstring to print out the first argument
- Using a for loop we iterate every argument (arg) that is passed to the arg_values and inside the loop we print what that arg relates to
This is a powerful concept as it means we can pass multiple unnamed arguments of multiple types (string, integer, float) to this function and the logic inside the function would work out what to do with it. Here it is simply printing out the values, but this could be a numerical summary function, as I will implement after this.
We then implement our call to this by using the function, which returns the below:
First argument is this is my normal argument Passed another argument (*arg_values): additional argument 1 Passed another argument (*arg_values): additional argument 2 Passed another argument (*arg_values): additional argument 3Essentially, we have found a way to capture the additional arguments passed by our miracle single asterisk. Let’s extend this to sum up numerical values.
Extending the args to work with numerical values
We will extend what we have practiced in the previous section to look at how we would use args to create a custom sum function.
As you have seen – you don’t actually have to name you function inputs *args they can be anything, so long as they are prefixed with an asterisk. This function:
- Initially sets the result to zero, as no calculations have been performed, and we need a way to initialise our variable
- I have added a print statement to the function to print the data type / structure that *range is wrapped up in (if you didn’t know – multiple arguments are stored as a tuple)
- The for loop loops through each value (val) in my range (this is what I called my multiple arguments parameter) and adds each value to the result, so each time it loops round it will append to the result until it has finished with every item in the tuple
- The final result is then returned by the function, using the return statement.
To call this function I simply pass the items I want to add together:
# Use the new function print(summer_function(20,40,60,80,100))What is returned to the console is the following:
<class 'tuple'> 300Simply that is how you can use arguments to extend the power of your functions immediately. The next use case we will look at keyword arguments (**kwargs).
What’s kwargs got to do with it?
Apologies for the shockingly bad Tina Turner headline on this title. Enough of my ramblings, what are kwargs. Kwargs are passed key work arguments that have a key and a value, much like how you would work with a Python dictionary.
Here we will implement a function that deals with multiple arguments and we will pass in a number of values that the function has never seen before:
Let’s decompose what this function is doing:
- Loops through the items in the k_wargs and exposed the key and the value when it loop through the number of keyword arguments
- prints the arguments that have been passed by key and value
- Checks logic to see if the key is equal to one of the values I will pass to the function
- Does the same in the next if statement
Running the function we get:
This produces:
first_name=Gary His name is Gary occupation=ML Engineer Lead fav_food=Fish Item contains his favourite food Fish.Because we can query by key and value we can also use conditional logic to look when there is a match.
Ordering arguments in a function
The correct ordering of arguments in a function is as so:
- Standard arguments
- *args arguments
- **kwargs arguments
These need to be specified in this order in every function
Unpacking args and kwargs
This can be really powerful. I will show you some examples of unpacking arguments from args and kwargs following.
Unpacking args
We will focus on unpacking arguments firstly, as this allows you to perform operations like merging multiple lists of the same size, or simply just passing a list of values. PyTorch uses kwargs unpacking a lot for passing the dictionary structure of a neural network to the model, so it is useful to start with these examples to get a good grasp of how to unpack our arguments.
The first example I will show is how to unpack a list of values and pass these unpacked arguments as seperate parameters into a sum function:
What is happening here?
- We have a standard sum function that expects three parameters to sum (x1, x2 & x3)
- I have a list – that contains three values within the list
- I use the special * (args asterisk) to say I want to unpack each one of the values in the list and pass these as the parameters to the function – so 20 becomes x1, 40 becomes x2 and 20 becomes x3. The function then adds these together and prints the result of 80.
Unpacking args by merging lists
Let’s use what we have learned previously to join two lists together, which is another novel way we could work with unpacking arguments.
Pardon the pun, but let’s unpack this:
- We create three list comprehensions (list of lists) where we just create a simple range of 10 values and then add to them in different ways and raise all them by the power of 3 (** is the power operator in Python)
- These three variables lists 1, 2 and 3 should all have the same length
- We then create a list of lists by passing the lists in as seperate arguments to the list – this sees each list as a separate item to add into the list
- When we print the length of the list we should get the length of the range – these do not need to be identically sized, as the previous example, as there is not a limited number of inputs to a list, unlike the 3 parameters we had in the previous example
The output of this code is:
30 [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 1728, 1000, 1331, 1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859]That’s all there is to it.
Unpacking kwargs
In this example, we will use the same motivation as we did before in merging lists, but this time we will use kwargs to merge two dictionaries together. Remember that kwargs have an associated key and value to their input parameters, so they work very much like a dictionary in Python.
Again, some unpacking required – stop it with the puns!:
- We create two dictionaries with keys x1, x2, x3 and x4 and their associated values, which in this case are numerical
- To merge these dicts we are going to unpack our kwargs using the special (** double asterisk) to do this
- Upon printing the merged dictionary we should have x1 through to x4 as keys in order:
I tend to use kwarg unpacking a lot when working with PyTorch and Transformer models, as normally you have an external modelling configuration that is a dictionary and you want to pass each one of the parameters into the model – by using model(**my_model_params) it means I do not have to extract them all separately to pass to the model each time. Such a time saver.
Closing
I hope you have found this post informative. I thought of coming at it from how I like to learn new concepts. Boiling them down to the simple components I know and then stepping through what each stage is doing.