Python Variable Length Arguments

In the last lesson, we learned about Python Keyword Arguments. Now let’s allow one function to accept any number of positional or keyword values.

Let’s Talk About Flexibility

Imagine we are at a restaurant. We want to order some dishes. Maybe we order one dish. Maybe we order five. We do not know in advance how many we will want.

A good waiter can handle any number of orders. They do not say, “Sorry, I can only take exactly three orders.”

That is what variable length arguments are for. They let our function accept any number of arguments. Not a fixed amount. But as many as the caller wants to provide.

Why Do We Need Variable Length Arguments in Python?

Sometimes we do not know how many arguments will be passed. Or we want to allow flexibility.

For example, a function that adds numbers. Maybe someone wants to add two numbers. Maybe someone wants to add ten. With variable length arguments, we can handle both.

The Two Types of Variable Length Arguments

Python has two types of variable length arguments.

  • *args — for positional arguments. Collects them into a tuple.
  • **kwargs — for keyword arguments. Collects them into a dictionary.

Let me explain each one.

*args — Variable Positional Arguments in Python

We put *args in the function definition. The * is the important part. The name args is just a convention. We can call it anything. But args is what everyone uses.

def add_all(*args):
total = 0
for num in args:
total += num
return total

Here, args is a tuple. It contains all the positional arguments passed to the function.

Let’s call it.

print(add_all(1, 2, 3))
print(add_all(5, 10))
print(add_all(1, 2, 3, 4, 5))
print(add_all())

Output

6
15
15
0

See? We can pass any number of arguments. Even zero. And the function handles it.

Inside the function, args is a tuple. So we can loop through it. Or check its length. Or do anything we would do with a tuple.

Let me show us another example.

def print_names(*names):
for name in names:
print(f"Hello, {name}")
print_names("Alex", "Sam", "John")

Output

Hello, Alex
Hello, Sam
Hello, John

That is *args. It collects all positional arguments into a tuple.

**kwargs — Variable Keyword Arguments in Python

We put **kwargs in the function definition. The ** is the important part. The name kwargs is just a convention. It stands for “keyword arguments.”

def print_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")

Here, kwargs is a dictionary. It contains all the keyword arguments passed to the function.

Let’s call it.

print_info(name="Alex", age=25, city="London")

Output

name: Alex
age: 25
city: London

We can pass any keyword arguments we want. The function collects them into a dictionary. Then we can loop through them.

Combining *args and **kwargs in Python

We can use both in the same function.

def show_all(*args, **kwargs):
print("Positional arguments:")
for arg in args:
print(f" {arg}")
print("Keyword arguments:")
for key, value in kwargs.items():
print(f" {key}: {value}")

Now call it:

show_all(1, 2, 3, name="Alex", age=25)

Output

Positional arguments:
1
2
3
Keyword arguments:
name: Alex
age: 25

That is very flexible. We can pass any number of positional arguments. And any number of keyword arguments. All in one function call.

The Order Matters in Python

When we use both, *args must come before **kwargs.

This is correct:

def good(*args, **kwargs):
pass

This is wrong:

def bad(**kwargs, *args): # Error!
pass

So let’s remember: positional first, then keyword.

Mixing with Regular Parameters in Python

We can also mix *args and **kwargs with regular parameters.

def greet(greeting, *names, punctuation="!"):
for name in names:
print(f"{greeting}, {name}{punctuation}")

Here, greeting is a regular parameter. *names collects the rest of the positional arguments. punctuation is a keyword-only parameter with a default.

Call it:

greet("Hello", "Alex", "Sam", "John")

Output

Hello, Alex!
Hello, Sam!
Hello, John!

We can also change the punctuation:

greet("Hi", "Alex", "Sam", punctuation=".")

Output

Hi, Alex.
Hi, Sam.

See how flexible it is? We can have a required first argument. Then any number of positional arguments. Then optional keyword arguments.

Python Variable Length Arguments: A Real-Life Example

Let’s build a function that creates a user profile. It takes a required username. Then any number of optional fields.

def create_profile(username, **details):
print(f"Username: {username}")
for key, value in details.items():
print(f"{key}: {value}")
print("-" * 20)
create_profile("alex123", age=25, city="London", is_admin=True)
create_profile("sam456", email="sam@example.com")

Output

Username: alex123
age: 25
city: London
is_admin: True
--------------------
Username: sam456
email: sam@example.com
--------------------

That is very useful. We can pass any extra details without changing the function.

Unpacking Arguments in Python

There is another side to this. We can also unpack a list or dictionary when calling a function.

If we have a list of values, we can unpack them with *.

def add(a, b, c):
return a + b + c
numbers = [1, 2, 3]
print(add(*numbers))

Output

6

The *numbers unpacks the list into three separate arguments.

Similarly, we can unpack a dictionary with **.

def greet(name, greeting):
print(f"{greeting}, {name}!")
info = {"name": "Alex", "greeting": "Hello"}
greet(**info)

Output

Hello, Alex!

This is the reverse of collecting. Instead of collecting arguments into a tuple or dictionary, we are spreading a tuple or dictionary into arguments.

Common Mistakes with Python Variable Length Arguments

Mistake 1: Forgetting the * or **

def add(args): # This takes one argument, not many
return sum(args)
add(1, 2, 3) # Error!

So what do we do? We add the star.

def add(*args):
return sum(args)

Mistake 2: Putting **kwargs Before *args

def bad(**kwargs, *args): # Error!
pass

So what do we do? We put *args first.

def good(*args, **kwargs):
pass

Mistake 3: Trying to Use args as a List

args is a tuple. It is immutable. If we need a list, we convert it.

def add(*args):
nums = list(args)
nums.append(10)
return sum(nums)

Mistake 4: Forgetting That kwargs Is a Dictionary

def show(**kwargs):
print(kwargs[0]) # Error! Dictionaries don't use numeric indices

So what do we do? We use the keys.

def show(**kwargs):
for key in kwargs:
print(kwargs[key])

Next, we will learn about Python Lambda Functions and create small one-expression functions.