*args & **kwargs

How does print() accept one argument or ten? How does a function pass along whatever it's given to another function? The answer is *args and **kwargs — Python's way of writing functions that accept a flexible, unknown number of inputs.

Learn *args & **kwargs in our free Python course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and a quick recall.

Part of the free Python course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Once you understand the star operators, a lot of "magic" library code suddenly reads clearly.

Imagine writing an add function. With fixed parameters you'd have to guess how many numbers the caller might pass:

*args fixes this. The star tells Python: "gather all the leftover positional arguments into a single tuple called args ":

Inside the function, args is just a normal tuple — you can loop over it, index it, or pass it to sum() .

While *args catches extra positional arguments, **kwargs catches extra keyword (named) arguments and stores them in a dictionary:

Each key=value the caller supplies becomes one entry in the kwargs dictionary. This is exactly how flexible configuration functions and many web framework APIs work under the hood.

You can combine regular parameters, *args , and **kwargs — but only in one specific order. Get it wrong and Python raises a SyntaxError :

The star operators work in reverse too. When you call a function, * spreads a list/tuple into positional arguments and ** spreads a dict into keyword arguments:

The most common professional reason to use both together is writing a wrapper that accepts anything and passes it straight through to another function — the heart of how decorators work:

Because timed doesn't care what arguments area needs, it can wrap any function at all. This "accept anything, forward everything" pattern is everywhere in real Python libraries.

These lines should define an averaging function and call it by unpacking a list. Reorder them so the output is Average: 20.0 .

Why: the def header (B) must come before its indented body (A). The values list (C) is created next, then the call (D) unpacks it with *values so the three numbers arrive as separate positional args. Their average is 20.0.

<class 'tuple'> — *args always collects extra positional arguments into a tuple, even though you call with a star.

7 — *[10, 3] spreads the list so a=10 and b=3 , giving 10 - 3 .

{" "} — merging dicts with ** lets later keys overwrite earlier ones, so a becomes 9.

Write a checkout function that totals any number of prices and accepts optional named settings.

Lesson complete — your functions are flexible now!

You can collect extra arguments with *args and **kwargs , order parameters correctly, unpack collections at the call site, and forward arguments through wrappers. This unlocks a huge amount of real-world Python code.

🚀 Up next: Lambda Functions — tiny one-line functions for sorting, mapping, and filtering.

Practice quiz

Inside def f(*args), what type is args?

  • list
  • dict
  • tuple
  • set

Answer: tuple. *args always collects extra positional arguments into a tuple.

Inside def g(**kwargs), what type is kwargs?

  • dict
  • tuple
  • list
  • set

Answer: dict. **kwargs collects extra keyword arguments into a dictionary.

Given def add(*args): return sum(args), what does add() return?

  • None
  • an error
  • ()
  • 0

Answer: 0. With no arguments, args is the empty tuple () and sum(()) is 0.

Given def sub(a, b): return a - b, what does sub(*[10, 3]) print?

  • 13
  • 7

Answer: 7. *[10, 3] spreads the list so a=10 and b=3, giving 10 - 3 = 7.

What is the result of {**{'a': 1}, **{'a': 9, 'b': 2}}?

  • {'a': 9, 'b': 2}
  • {'a': 1, 'b': 2}
  • {'a': 10, 'b': 2}
  • an error

Answer: {'a': 9, 'b': 2}. When merging dicts with **, later keys overwrite earlier ones, so a becomes 9.

Which parameter order is valid in a function signature?

  • def f(**kwargs, *args)
  • def f(*args, a, **kwargs)
  • def f(a, *args, **kwargs)
  • def f(*args, a)

Answer: def f(a, *args, **kwargs). The required order is: normal params, then *args, then keyword-only params, then **kwargs.

In a function DEFINITION, what does the * in *args do?

  • Spreads a tuple into arguments
  • Collects extra positionals into a tuple
  • Multiplies the arguments
  • Nothing

Answer: Collects extra positionals into a tuple. In a definition the star collects; at a call site it spreads. Same symbol, mirror jobs.

A parameter listed AFTER *args in a signature becomes...

  • positional-only
  • optional
  • ignored
  • keyword-only

Answer: keyword-only. Anything after *args must be passed by name, making it keyword-only.

What does [*[1, 2], *[3, 4]] evaluate to?

Unpacking with * spreads both lists into one flat list [1, 2, 3, 4].

Why is *args/**kwargs ideal for writing a wrapper or decorator?

  • It runs faster
  • It hides the original function
  • It forwards any arguments straight through to the wrapped function
  • It removes default values

Answer: It forwards any arguments straight through to the wrapped function. The wrapper accepts anything and forwards it with func(*args, **kwargs), so it can wrap any function.