*args and **kwargs
Intro
If you're serious about improving your programming skills, consider subscribing to my newsletter, it's free and keeps you updated with my latest python and programming tips.
In this article, I'll explain what *args and **kwargs are, their use, and a common mistake made while using them. To avoid wasting time, let's get right into it!
What are *args and **kwargs?
*args and **kwargs are a special type of argument, used when you don't know yet how many arguments are going to be passed in a function.
For example, say you want to write a function that takes n numbers as input and outputs their sum (different from the python sum()
function as this one takes an array as input), you'd have to know what n was exactly to write the function:
def user_sum(n1, n2, n3):
return n1+n2+n3
print(user_sum(1,2,3,4))
Output:
Traceback (most recent call last):
File "C:\Users\gerva\OneDrive\Bureau\args and kwargs.py", line 4, in
print(user_sum(1,2,3,4))
TypeError: user_sum() takes 3 positional arguments but 4 were given
Knowing about *args and **kwargs will let us work around that. Let's start with *args. It is used for handling an unknown amount of positional arguments, let's check out how it works:
def args_function(*args):
print(args)
print(type(args))
args_function(1,2,3,4)
Output:
(1, 2, 3, 4)
<class 'tuple'>
As we can see, the *args arguments collects all positional arguments and stores them in the args variable as a tuple. Using that knowledge, we can rewrite the previous sum function:
def user_sum(*args):
total = 0
for number in args:
if type(number) is int or type(number) is float:
total += number
return total
result = user_sum(1,2,3,4,5,6,7,8)
print(result)
Output:
36
The reason I checked the type of each argument here is that, just like a normal iterable, we can put different variable types and the *args argument will handle them all the same:
def check_type(*args):
for element in args:
print(element, type(element))
check_type(1, True, "hello", 0.0, None, b"hello", [1,2], (1,2), 1j)
Output:
1 <class 'int'>
True <class 'bool'>
hello <class 'str'>
0.0 <class 'float'>
None <class 'NoneType'>
b'hello' <class 'bytes'>
[1, 2] <class 'list'>
(1, 2) <class 'tuple'>
1j <class 'complex'>
Now, let's talk about the **kwargs argument. As the name might suggest, this is used to handle multiple keyword arguments. Let's check it out as well:
def check_kwargs(**kwargs):
print(kwargs)
print(type(kwargs))
check_kwargs(a=1, b=2, c=3)
Output:
{'a': 1, 'b': 2, 'c': 3}
<class 'dict'>
So, to actually get the passed values, we could write:
def get_kwvalues(**kwargs):
for kw in kwargs:
print(kwargs[kw])
get_kwvalues(a="hello", b=123, c=[0,1])
Output:
hello
123
[0, 1]
Well, this is also pretty interesting, let's try to modify our previous sum function to incorporate keyword arguments!
def user_sum_and_multiply(*args, **kwargs):
total = 0
for number in args:
if type(number) is int or type(number) is float:
total += number
for kw in kwargs:
if type(kwargs[kw]) is int or type(kwargs[kw]) is float:
total *= kwargs[kw]
return total
result = user_sum_and_multiply(1,2,3,4,5,6,7,8, a=2, b=3)
print(result)
Output:
216
Common mistake
The main thing to remember while using *args and **kwargs is that normal positional arguments and keyword arguments can still be used in the function and will be taken into account, but their position matter:
- positional arguments must go before the *args
- Keyword arguments must go between the *args and **kwargs
Here is an example, this is valid:
def test(a, b, c, *args, kw1="hello", kw2=10, **kwargs):
print(a)
print(b)
print(c)
print(args)
print(kw1)
print(kw2)
print(kwargs)
test(1, 2, 3, "this is in *args", kw1=7, var1=True, var2=False) #for example, kw2 will not be modified
Output:
1
2
3
('this is in *args',)
7
10
{'var1': True, 'var2': False}
While this is not valid:
def test(*args, a, b, c, **kwargs, kw1="hello", kw2=10):
print(a)
print(b)
print(c)
print(args)
print(kw1)
print(kw2)
print(kwargs)
Output:
File "C:\Users\gerva\OneDrive\Bureau\args and kwargs.py", line 1
def test(*args, a, b, c, **kwargs, kw1="hello", kw2=10):
^^^
SyntaxError: invalid syntax
Thanks a lot for reading until the end, I hope you learned something and consider subscribing to my newsletter to learn more!