FunctionsIntermediate8 min35 / 63

*args and **kwargs

Learn how to write flexible Python functions that accept any number of arguments using *args and **kwargs.

Imagine you are building a function to greet your friends. You have three friends today, but tomorrow you might have ten. Do you write a different function for each count? No — that would be exhausting!

Python gives you two special tools — *args and **kwargs — that let your functions accept as many arguments as needed, without knowing the count in advance. Once you understand them, your functions will feel like superpowers.

See it in action

Visual walkthrough1 / 5
1

Functions That Take Anything

What if you want a function that works with 2 arguments today and 10 tomorrow? *args and **kwargs let your functions accept as many inputs as needed — no rewriting required.

These are not special keywords — the magic is in the * and ** symbols, not the names 'args' or 'kwargs'.

#Collecting Positional Arguments with *args

Think of it like

Think of *args as a shopping bag

You do not know exactly how many items you will pick up at the store. A bag collects everything you toss in. *args is that bag for positional arguments — however many you pass, they land together in a tuple inside your function.

*args collects every extra positional argument into a tuple.
def add_all(*args):
    print(type(args))  # it is always a tuple
    total = 0
    for number in args:
        total += number
    return total

print(add_all(1, 2))           # two numbers
print(add_all(10, 20, 30))     # three numbers
print(add_all(5, 5, 5, 5, 5)) # five numbers

#Collecting Keyword Arguments with **kwargs

**kwargs gathers all keyword arguments into a plain dict.
def show_profile(**kwargs):
    print("User profile:")
    for key, value in kwargs.items():
        print(f"  {key}: {value}")

show_profile(name="Alice", age=30, city="London")

#Combining Everything — and the Required Order

You can mix all four kinds of parameters in one function. Python enforces a strict order:

  1. Regular positional parameters
  2. *args
  3. Keyword-only parameters (with defaults)
  4. **kwargs
All four parameter kinds working together in the correct order.
def make_order(restaurant, *dishes, tip=0, **extras):
    print(f"Restaurant: {restaurant}")
    print(f"Dishes: {dishes}")
    print(f"Tip: {tip}%")
    print(f"Special requests: {extras}")

make_order(
    "Pasta House",
    "Carbonara", "Tiramisu",
    tip=15,
    allergy="nuts", seat="window"
)
Common mistake

Order matters — always!

Putting **kwargs before *args causes a SyntaxError. Python enforces the order: regular params → *args → keyword-only → **kwargs. Mix them up and your code will not even start.

#Unpacking at the Call Site

* and ** unpack existing collections into arguments when calling a function.
def greet(first, last, greeting="Hello"):
    print(f"{greeting}, {first} {last}!")

# Unpack a list into positional args with *
name_parts = ["Jane", "Doe"]
greet(*name_parts)

# Unpack a dict into keyword args with **
options = {"first": "John", "last": "Smith", "greeting": "Hi"}
greet(**options)
Tip

Unpacking is great for forwarding settings

Store your config in a dictionary, then pass it anywhere with function(**config). No need to type every key out individually — just unpack and go.

Quick check

What type does Python use to store values collected by *args inside a function?

Key takeaways

  • `*args` collects any number of extra positional arguments into a **tuple** inside your function.
  • `**kwargs` collects any number of extra keyword arguments into a **dict** inside your function.
  • Parameter order is strict: regular params → `*args` → keyword-only → `**kwargs`.
  • At the call site, `*iterable` unpacks into positional arguments and `**mapping` unpacks into keyword arguments.
  • These tools let you write flexible, reusable functions that handle varying inputs gracefully.
Practice challenges
Test yourself · earn XP
0/4
Predict the output#1

What does this code print?

predict-output
def add_all(*args):
    total = 0
    for n in args:
        total += n
    return total

print(add_all(4, 6))
print(add_all(1, 2, 3))
Fix the bug#2

This code has a bug. What is wrong?

fix-bug
def show_info(**kwargs, *args):
    for key, value in kwargs.items():
        print(f"{key}: {value}")
    for item in args:
        print(item)

show_info(color="red", "apple", "banana")
Fill in the blank#3

Complete the code so that calling greet(**options) prints "Hi, Ada!".

def greet(name, greeting):
    print(f"{greeting}, {name}!")

options = {"name": "Ada", "greeting": "Hi"}
greet(options)
Reorder the lines#4

Put these lines in the right order to define and call a function that prints each topping passed to it.

1
    for topping in args:
2
list_toppings("cheese", "peppers", "olives")
3
        print(topping)
4
def list_toppings(*args):
Your turn
Practice exercise

Write a function called summarize that accepts a title (regular parameter), any number of bullet points (via args), and any number of metadata fields (via *kwargs). It should print the title on the first line, each bullet point prefixed with '- ', and then each metadata key-value pair. Test it with at least two bullet points and two keyword arguments.

Try it live — edit the code and hit Run to execute real Python:

solution.py · editable