Python Variable Length Arguments

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 called numbers.
  • 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

30
15
7
0

One 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 every name=value pair into a dictionary called kwargs.
  • 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: Riya
role: Engineer
city: Berlin

Notice 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: Pizza
Extras: ('cheese', 'olives')
Details: {'size': 'large', 'crust': 'thin'}

⚠️ Common Mistakes

A few things trip people up the first time.

  • Putting a plain parameter after *args by accident. Once you write *args, any parameter after it becomes keyword-only. The caller MUST pass it by name. So def bad(*args, item): is legal, but bad(1, 2, 3) fails with TypeError: missing 1 required keyword-only argument: item. You would have to call bad(1, 2, item=3). If you meant item to be an ordinary required value, put it first: def good(item, *args):.
# ❌ Surprise: item is now keyword-only, so bad(1, 2, 3) raises TypeError
def bad(*args, item):
...
# βœ… Good: required parameter first, then *args
def good(item, *args):
...
  • Thinking args is 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 with list(args).

  • Forgetting the star when you read it. Inside the function you use the plain name args or kwargs. The * and ** go only in the function definition (and when unpacking on a call).

# ❌ Avoid: there is no variable called *args inside the body
def total(*args):
return sum(*args) # this unpacks, not what we want here
# βœ… Good: use the plain name args
def total(*args):
return sum(args)

βœ… Best Practices

Keep these habits and your code stays easy to read.

  • Stick with the names args and kwargs. Other Python developers expect them, so your code reads clearly. Use a more descriptive name like *numbers only 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 *args to look clever.
  • Put a docstring on functions that use *args or **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. 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. 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. 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. 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.

Lambda Functions

Share & Connect