Python Variable Length Arguments
Table of Contents + β
In the last lesson you learned Keyword Arguments. There you pass values by name so the order does not matter. That works great when you know exactly which arguments a function takes. But what if you do not? Say you want a function that adds numbers. Sometimes there are three numbers. Sometimes there are ten. You cannot write a fixed parameter for each one. This lesson shows you how Python lets a single function accept any number of arguments.
π€ Why Variable Length Arguments?
Here is the pain. You write a function add(a, b) to add two numbers. Then you need to add three. So you write add(a, b, c). Then four. You keep editing the function every time the count changes. That is annoying. And it does not scale.
The fix is simple. Python gives you a way to say βcollect everything that comes in, however many there are.β You write one function and it handles two numbers or two hundred. The tool for this is called variable length arguments. You create it with a * or ** in front of a parameter name.
π§© What *args Means
Think of *args like a shopping bag. People hand you items one by one. You do not count them first. You just drop each one into the bag. At the end the bag holds whatever came in.
When you put a * in front of a parameter, Python takes all the extra positional arguments and packs them into a single tuple. A tuple is just an ordered group of values. The name args is only a convention. The real magic is the *. You could call it *numbers or *things and it would work the same.
Here is the smallest example. This function takes any number of values and prints the tuple it collected.
def show(*args): print(args)
show(1, 2, 3)show("a", "b")show()The output shows that each call packs its arguments into a tuple.
Output
(1, 2, 3)('a', 'b')()See what happened? The first call collected three values. The second collected two. The third got nothing, so args is an empty tuple. The function never changed. It just adapts to whatever you give it.
β A Real Example: Adding Any Count of Numbers
Now let us build something useful. We want a sum_all function that adds however many numbers you pass it. Since args is a tuple, you can loop over it like any other group of values.
def sum_all(*numbers): total = 0 for n in numbers: total += n return total
print(sum_all(10, 20))print(sum_all(1, 2, 3, 4, 5))print(sum_all(7))print(sum_all())Let us walk through it.
def sum_all(*numbers):β the*tells Python to gather every value into a tuple callednumbers.total = 0β we start a running total at zero.for n in numbers:β we go through each number that was collected.total += nβ we add each one to the total.return totalβ we hand back the final sum.
Here is what it prints.
Output
301570One function handled four different counts. Two numbers, five numbers, one number, even zero. You did not touch the function in between. That is the whole point.
Note
Python actually ships with a built-in sum() that adds the items in a list or tuple. We wrote sum_all by hand here so you can see how *args works. In real code, sum([10, 20]) would do the job.
π What **kwargs Means
So *args collects extra positional arguments. There is a matching tool for keyword arguments. It uses two stars: **kwargs.
When you put ** in front of a parameter, Python takes all the extra keyword arguments and packs them into a dictionary. A dictionary stores values by name. So each keyword becomes a key and its value becomes the value. Just like before, the name kwargs is only a convention. The ** is what matters.
Here is a small example. This function prints each key and its value.
def show_details(**kwargs): for key, value in kwargs.items(): print(f"{key}: {value}")
show_details(name="Riya", role="Engineer", city="Berlin")Let us read it.
def show_details(**kwargs):β the**gathers everyname=valuepair into a dictionary calledkwargs.for key, value in kwargs.items():β.items()gives us each key and its value together.print(f"{key}: {value}")β we print them on one line using an f-string.
Here is the result.
Output
name: Riyarole: Engineercity: BerlinNotice you never said up front that the function takes name, role, or city. The caller decided that. The function just accepts whatever keyword pairs arrive and walks through them. This is handy when you do not know the labels ahead of time. Think of building a user profile where every person fills in different fields.
πͺ’ One Star vs Two Stars
The two look alike but do different jobs. Here is the quick split.
| Syntax | Collects | Packs into |
|---|---|---|
*args | extra positional arguments (no name) | a tuple |
**kwargs | extra keyword arguments (name=value) | a dictionary |
You can even use both in the same function. Normal parameters come first, then *args, then **kwargs. This function shows all three working together.
def make_order(item, *extras, **details): print(f"Item: {item}") print(f"Extras: {extras}") print(f"Details: {details}")
make_order("Pizza", "cheese", "olives", size="large", crust="thin")The required item grabs the first value. The *extras collects the loose positional ones. The **details collects the named ones.
Output
Item: PizzaExtras: ('cheese', 'olives')Details: {'size': 'large', 'crust': 'thin'}β οΈ Common Mistakes
A few things trip people up the first time.
- Putting a plain parameter after
*argsby accident. Once you write*args, any parameter after it becomes keyword-only. The caller MUST pass it by name. Sodef bad(*args, item):is legal, butbad(1, 2, 3)fails withTypeError: missing 1 required keyword-only argument: item. You would have to callbad(1, 2, item=3). If you meantitemto be an ordinary required value, put it first:def good(item, *args):.
# β Surprise: item is now keyword-only, so bad(1, 2, 3) raises TypeErrordef bad(*args, item): ...
# β
Good: required parameter first, then *argsdef good(item, *args): ...-
Thinking
argsis a list. It is a tuple. So you can loop over it and read by index, but you cannot change it in place. If you need to add or remove items, turn it into a list first withlist(args). -
Forgetting the star when you read it. Inside the function you use the plain name
argsorkwargs. The*and**go only in the function definition (and when unpacking on a call).
# β Avoid: there is no variable called *args inside the bodydef total(*args): return sum(*args) # this unpacks, not what we want here
# β
Good: use the plain name argsdef total(*args): return sum(args)β Best Practices
Keep these habits and your code stays easy to read.
- Stick with the names
argsandkwargs. Other Python developers expect them, so your code reads clearly. Use a more descriptive name like*numbersonly when it truly makes the meaning obvious. - Use variable length arguments only when the count really is unknown. If a function always takes two values, just write two parameters. Do not reach for
*argsto look clever. - Put a docstring on functions that use
*argsor**kwargs. The parameters are open-ended, so a one-line note about what they expect saves the reader a lot of guessing.
π§© What Youβve Learned
β
A * in front of a parameter collects extra positional arguments into a tuple, so one function can take any number of values.
β
A ** in front of a parameter collects extra keyword arguments into a dictionary, keyed by the names the caller used.
β
The names args and kwargs are just convention; the stars do the real work.
β
When you mix them, the order is fixed: normal parameters, then *args, then **kwargs.
β
You built a sum_all function that adds two numbers or two hundred without changing the function.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does *args collect, and what type does it become inside the function?
Why: A single star gathers the extra positional arguments and packs them into a tuple.
- 2
What does **kwargs collect, and what type does it become?
Why: A double star gathers the extra keyword (name=value) arguments into a dictionary.
- 3
When a function mixes all three, what is the correct order of parameters?
Why: Python requires normal parameters first, then *args, then **kwargs.
- 4
Inside the function body, how do you refer to the collected values when the parameter is *args?
Why: The star is only used in the definition; inside the body you use the plain name args.
π Whatβs Next?
You can now write functions that accept any number of arguments. Next we will look at a way to write tiny one-line functions without the full def syntax.