*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.

What You'll Learn in This Lesson

1 The Problem *args Solves

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() .

🏷️ **kwargs — Flexible Named Arguments

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.

2 The Required Parameter Order

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

3 The Other Direction: Unpacking at the Call Site

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 Classic Use: Forwarding 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.

🧩 Reorder Challenge

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.

🧠 Quick Recall

<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 .

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

📋 Star Operator Quick Reference

Syntax

Where

Does

*args

Definition

Collect extra positionals → tuple

**kwargs

Collect extra keywords → dict

*list

Call site

Spread list → positional args

**dict

Spread dict → keyword args

{**a, **b}

Literal

Merge two dictionaries

Frequently Asked Questions

🎯 Mini Challenge: Flexible Shopping Cart

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.

Continue this course