What are *args and **kwargs in Python?
*args collects extra positional arguments into a tuple; **kwargs collects extra keyword arguments into a dict - both allow functions to accept variable numbers of arguments.
Python
Overview
`*args` and `**kwargs` are conventions for accepting variable numbers of arguments. The `*` and `**` are the actual syntax - `args` and `kwargs` are just the conventional names (you can call them anything). They are used extensively in Python frameworks and when wrapping or decorating functions.
Key Points
- •`*args` in a function signature: collects extra positional args into a tuple.
- •`**kwargs` in a function signature: collects extra keyword args into a dict.
- •Order in signature: `(pos_args, *args, keyword_only, **kwargs)`.
- •Calling a function: `*iterable` unpacks as positional args; `**dict` unpacks as keyword args.
- •Keyword-only parameters: any parameter after `*args` must be passed by name.
Examples
*args: accept any number of positional arguments
pythondef add(*numbers):
return sum(numbers)
add(1, 2) # 3
add(1, 2, 3, 4, 5) # 15
add() # 0
# numbers is a tuple inside the function
def show(*args):
print(type(args), args)
show('a', 'b') # <class 'tuple'> ('a', 'b')**kwargs: accept any number of keyword arguments
pythondef configure(**options):
for key, value in options.items():
print(f"{key} = {value}")
configure(theme='dark', lang='en', debug=True)
# theme = dark
# lang = en
# debug = TrueCombining regular, *args, and **kwargs
pythondef log(level, *messages, separator=' | ', **metadata):
joined = separator.join(messages)
print(f"[{level}] {joined}", metadata)
log('INFO', 'User login', 'Session started', user_id=42, ip='127.0.0.1')
# [INFO] User login | Session started {'user_id': 42, 'ip': '127.0.0.1'}separator is keyword-only (after *args); **metadata collects anything else.
Unpacking when calling a function
pythondef greet(first, last, greeting='Hello'):
print(f"{greeting}, {first} {last}!")
args = ('Alice', 'Smith')
kwargs = {'greeting': 'Hi'}
greet(*args, **kwargs) # Hi, Alice Smith!
# Very common with decorators to forward all arguments
def decorator(func):
def wrapper(*args, **kwargs):
print("before")
return func(*args, **kwargs) # forward everything to original
return wrapperPro Tip
When writing a wrapper or decorator, always use `(*args, **kwargs)` to forward all arguments transparently. This ensures the wrapper works for any function it wraps, regardless of its signature.