*args and **kwargs

Accept an arbitrary number of positional or keyword arguments in a function definition.

                def f(*args, **kwargs): ...
              

Purpose

A parameter prefixed with * collects any extra positional arguments into a tuple; one prefixed with ** collects any extra keyword arguments into a dict. Together they let a function accept a variable, unspecified-in-advance number of arguments.

Example

def total(*numbers: float) -> float:
    return sum(numbers)


def describe(**details: str) -> str:
    parts = [f"{key}={value}" for key, value in details.items()]
    return ", ".join(parts)


total(1.5, 2.25, 3.0)                    # 6.75
describe(name="Ada", role="engineer")    # "name=Ada, role=engineer"

Behavior notes

  • The names args and kwargs are a strong convention, not a requirement β€” *items or **options work identically. What matters is the */** prefix, not the name.
  • *args collects positional arguments beyond the ones already named; **kwargs collects keyword arguments that don’t match any named parameter. A function can have both, in that order, plus named parameters before them.
  • Since Python 3.7, a dict (and so **kwargs) preserves insertion order β€” iterating over kwargs.items() visits entries in the order the caller passed them.
  • The reverse operation β€” spreading an existing sequence or mapping into a call β€” uses the same */** symbols at the call site: total(*[1.5, 2.25, 3.0]) or describe(**{"name": "Ada"}). Same symbols, opposite direction: collecting when defining, spreading when calling.

Common mistakes

  • Adding named parameters after **kwargs in a definition β€” this isn’t allowed; **kwargs (like *args) has to be among the last parameters.
  • Reaching for **kwargs for a fixed, known set of options instead of naming them directly with defaults β€” named parameters are more discoverable and let type checkers and IDEs catch typos that **kwargs would silently swallow into the dict instead of flagging.

Implementation notes

Argument-collection semantics for *args/**kwargs are defined by the language grammar β€” identical across conforming implementations.

Taught in these lessons

Related reference