What are `*args` and `**kwargs`, and how do you use them together?
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.