Using *args in Python3 to define a function that takes a variable number of arguments (or none at all)
By: Joe Cardillo
Tags: Python, Learning To Code, Python3, Programming, Coding

Using *args in Python3 to define a function that takes a variable number of arguments (or none at all)

Photo by Janko Ferlič on Unsplash

The other day I ran into a problem asking me to provide one kind of output if an argument was given, and another if no argument was given.

For example — given a book, return the message:

My favorite book is X.

Where X is the given book.

However, if the book is missing, return the string:

I don't like to read.

The exercise came with the following function to manipulate:

def fav_book(book):

pass

I wrongly assumed I could only change text in the function suite (where pass was), instead of the argument itself. As a result, the first function I came up with was something like this:

def fav_book(book):

if book:

print(f"My favorite book is {book}.")

else:

print("I don't like to read.")

Essentially saying, “If the book exists when the function is called, tell us your favorite book. Otherwise (else) tell us you don’t like to read.”

This worked when passing the function an argument:

fav_book("Crime and Punishment")

My favorite book is Crime and Punishment.

However, when running this with no argument given I was getting a TypeError :

fav_book()

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: fav_book() missing 1 required positional argument: 'book'

Using Try / Except

Next I tried accounting for this TypeError using a try statement. The idea being: “Try to run this piece of code (or in my case, this print statement), and if you get an error, print something else.” But this also left me high and dry:

def fav_book(book):

try:

print(f"My favorite book is {book}.")

except TypeError:

print("I don't like to read.")

When I called the function with an argument, it worked. But again, without an argument it failed with the same TypeError.

I was banging my head against the wall for awhile on this because it seemed obvious. If I get a TypeError, it should not bother to tell me about it, and should instead run the “I don’t like to read” statement.

Eventually I realized this was likely happening because we never get to the except statement in the first place. In other words, since I defined the function with an argument, I can’t call it without any arguments.

Predefining an argument’s value in the function

I came across a bit of code online that seemed like a viable workaround. It made me realize you can set an argument equal to something within the function. Like this:

def fav_book(book="I don't like to read."):

if book != "I don't like to read.":

print(f"My favorite book is {book}.")

else:

print(book)

This was news to me, since I’m new at this. This works, but it looks a little messy, if only because there’s a long string of text in-between the parenthesis.

Solving the problem with *args

Eventually I came across the concept of *args which lets you take in more arguments than the number you defined, or zero arguments.

Which led me to this as an option:

def fav_book(*books):

if books:

for book in books:

print(f"My favorite book is {book}.")

else:

print("I don't like to read.")

*books — This lets me take in as many books as possible into the function, since who really only has one favorite book, am I right?

— This lets me take in as many books as possible into the function, since who really only has one favorite book, am I right? if statement — This loops through all the books provided when the function is called, and prints them out, like so:

fav_book("Crime and Punishment", "Fight Club", "Tao Te Ching")

My favorite book is Crime and Punishment.

My favorite book is Fight Club.

My favorite book is Tao Te Ching.

else statement — If no arguments are given, the else statement calls the print(“I don’t like to read.”) line.

fav_book()

I don't like to read.

I’m sure there are more elegant and intuitive ways to solve this, so feel free to share them in the comments if my newbie code is making you cringe.