The special syntax *args in function definitions in python is used to pass a variable number of arguments to a function. It is used to pass a non-keyworded, variable-length argument list.
The syntax is to use the symbol to take in a variable number of arguments; by convention, it is often used with the word args.
What *args
allows you to do is take in more arguments than the number of formal arguments that you previously defined. With **args
, any number of extra arguments can be tacked on to your current formal parameters (including zero extra arguments).
Don’t let the syntax scare you. These aren’t super special parameters. They’re not even that fancy, and we’re going to learn how to use them.
There are two concepts we need to separate in order to learn what *args
and **kwargs
are.
The first is the difference between positional and keyword arguments. In the most basic of functions, we play a matching game — argument 1 goes with parameter 1, argument 2 goes with parameter 2, and so on.
def printThese(a,b,c):
print(a, "is stored in a")
print(b, "is stored in b")
print(c, "is stored in c")
printThese(1,2,3)
"""
1 is stored in a
2 is stored in b
3 is stored in c
"""
All three arguments are required. Missing one will cause an error.
def printThese(a,b,c):
print(a, "is stored in a")
print(b, "is stored in b")
print(c, "is stored in c")
printThese(1,2)
"""
TypeError: printThese() missing 1 required positional argument: 'c'
"""
If we give a parameter a default value in the function definition, then it becomes optional.
def printThese(a,b,c=None):
print(a, "is stored in a")
print(b, "is stored in b")
print(c, "is stored in c")
printThese(1,2)
"""
1 is stored in a
2 is stored in b
None is stored in c
"""
Additionally, these optional parameters also become keyword-eligible, meaning you can specify the parameter name in the function call to map it accordingly.
Let’s make all three variables default to None
and watch how we can still map them irregardless of order.
def printThese(a=None,b=None,c=None):
print(a, "is stored in a")
print(b, "is stored in b")
print(c, "is stored in c")
printThese(c=3, a=1)
"""
def printThese(a=None,b=None,c=None):
print(a, "is stored in a")
print(b, "is stored in b")
print(c, "is stored in c")
printThese(c=3, a=1)
"""
1 is stored in a
None is stored in b
3 is stored in c
"""
Let me start by saying I love the name of this operator — it’s so … visual. The *
is most commonly associated with multiplication, but in Python it doubles as the splat operator.
I think of this operator as a piñata. I’ve described the spread operator — the JavaScript equivalent of splat — as unpacking a series of dominoes to form a single larger sequence, but splat warrants a more forceful analogy.
A simple example will make this more clear.
a = [1,2,3]
b = [*a,4,5,6]
print(b) # [1,2,3,4,5,6]
In the code example, we’re taking the contents of a
and splattering (unpacking) it into our new list b
.
So we know the splat operator unpacks multiple values, and there are two types of function parameters. Well, if you haven’t figured it out by now, *args
is short for arguments, and **kwargs
is short for keyword arguments.
Each is used to unpack their respective argument type, allowing for function calls with variable-length argument lists. For example, let’s create a function to print a student’s test scores.
def printScores(student, *scores):
print(f"Student Name: {student}")
for score in scores:
print(score)
printScores("Jonathan",100, 95, 88, 92, 99)
"""
Student Name: Jonathan
100
95
88
92
99
"""
Whoa, wait. I didn’t name it *args
? That’s right, “args” is a standard convention but still just a name. The secret revealed, in *args
, the single asterisk is the real player here, creating a list whose contents are positional arguments — after those defined — from the function call.
With that cleared up, **kwargs
should be a easy to digest. The name doesn’t matter, but the double asterisks create a dictionary whose contents are keyword arguments — after those defined — from a function call.
To illustrate this, let’s create a function to print the names of a person’s pets.
def printPetNames(owner, **pets):
print(f"Owner Name: {owner}")
for pet,name in pets.items():
print(f"{pet}: {name}")
printPetNames("Jonathan", dog="Brock", fish=["Larry", "Curly", "Moe"], turtle="Shelldon")
"""
Owner Name: Jonathan
dog: Brock
fish: ['Larry', 'Curly', 'Moe']
turtle: Shelldon
"""
A few words of wisdom to help you avoid common pitfalls and expand your knowledge.
*args,
**kwargs
as a standard convention to catch positional and keyword arguments**kwargs
before *args
, or you’ll receive an error**kwargs
where the value is meant to be passed as a **kwarg
but is unknowingly the name of a keyword parameterPlease write comments if you find anything incorrect, or you want to share more information about the topic discussed above. Thank you!
#python #programming #web-development #machine-learning #developer