Skip to content
UniCircle
EasyConceptualFunction parameters

*args, **kwargs, and keyword-only parameters

Question PY-FUN-004

What do *args and **kwargs mean in a function definition? What do * and ** do in a function call? What is a keyword-only parameter?

Show the explanation

In a definition, they collect extra arguments

Python
def log(level, *args, sep=" ", **kwargs):
    # args   -> a tuple of the extra positional arguments
    # kwargs -> a dict of the extra keyword arguments
    print(level, sep.join(map(str, args)), kwargs)

log("INFO", "user", 42, sep="|", ip="10.0.0.1")
# INFO user|42 {'ip': '10.0.0.1'}

The names args and kwargs are only a convention. The * and ** do the work.

In a call, they unpack

Python
point = (3, 4); opts = {"sep": "-"}
log("DEBUG", *point, **opts)      # same as log("DEBUG", 3, 4, sep="-")

Keyword-only parameters come after *args or a bare *, and callers must pass them by name:

Python
def connect(host, port, *, timeout=5, retries=3): ...
connect("db", 5432, timeout=10)   # OK
connect("db", 5432, 10)           # TypeError

This stops mistakes such as passing arguments in the wrong order, and makes call sites easier to read.

Positional-only parameters (Python 3.8+) come before a /: def f(a, b, /, c). Callers cannot pass a and b by name, which lets you rename them later without breaking anyone.

The full order is def f(pos_only, /, normal, *args, kw_only, **kwargs).

Typical uses: wrapper functions and decorators that forward everything (return func(*args, **kwargs)), and functions such as print or max that take any number of arguments.

Original UniCircle question. Last reviewed 22 Oct 2026.