What are `*args` and `**kwargs`, and how do you use them together?

4 minbeginnerfundamentalsfunctions

Quick Answer

`*args` collects extra **positional** arguments into a `tuple`; `**kwargs` collects extra **keyword** arguments into a `dict`. They let a function accept a variable number of arguments and are commonly used for wrapper/proxy functions (e.g., decorators) that forward whatever they receive to another callable. Order matters: positional-only, then `*args`, then keyword-only, then `**kwargs`.

Detailed Answer

Collecting variable arguments

def summarize(*args, **kwargs):
    print(args)     # tuple of positional args
    print(kwargs)   # dict of keyword args

summarize(1, 2, 3, name="Ada", active=True)
# (1, 2, 3)
# {'name': 'Ada', 'active': True}

*args gathers any positional arguments beyond the named parameters into a tuple; **kwargs gathers any keyword arguments not matched by name into a dict.

Forwarding arguments (the most common real use)

def logged(func):
    def wrapper(*args, **kwargs):
        print(f"calling {func.__name__}")
        return func(*args, **kwargs)   # forward everything, unchanged
    return wrapper

This is why almost every decorator's wrapper signature is (*args, **kwargs) — it makes the wrapper work for any wrapped function signature without needing to know it in advance.

Combining with named and keyword-only parameters

def request(url, *args, timeout=30, **kwargs):
    ...

Parameter order must be: positional params → *args → keyword-only params (anything after *args must be passed by name) → **kwargs. This lets you mix a required positional API with an "escape hatch" for extra options.

Unpacking at the call site

The same */** syntax unpacks a sequence or mapping into a call:

values = (1, 2, 3)
options = {"name": "Ada"}
summarize(*values, **options)   # same as summarize(1, 2, 3, name="Ada")

Interview-ready summary: *args/**kwargs are Python's mechanism for variadic functions — *args as a tuple of extra positional arguments, **kwargs as a dict of extra keyword arguments. They're essential for writing generic wrappers (decorators, proxies) that forward calls without caring about the wrapped function's exact signature.