Understand and Use *args and **kwargs in Python

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.

📙 20 Best Python Books for Beginners and Experienced Coders

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.

Positional vs. Keyword Arguments

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
"""

The Splat Operator

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.

How To Use *args and **kwargs

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
"""

Parting Words

A few words of wisdom to help you avoid common pitfalls and expand your knowledge.

  • Use *args, **kwargs as a standard convention to catch positional and keyword arguments
  • You cannot place **kwargs before *args, or you’ll receive an error
  • Beware of conflicts between keyword parameters and **kwargs where the value is meant to be passed as a **kwarg but is unknowingly the name of a keyword parameter
  • You can use the splat operator in function calls as well

Please 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

Understand and Use *args and **kwargs in Python
1 Likes186.90 GEEK