Python Functions
Python *args and **kwargs
*args and **kwargs let a Python function accept any number of extra arguments — *args collects extra positional values into a tuple, and **kwargs collects extra keyword values into a dictionary.
What *args Does
The single asterisk before a parameter name tells Python to pack every extra positional argument into a tuple called args (the name itself is just a convention — only the * matters). This is handy when you do not know how many values the caller will pass.
def add_all(*args):
print(args, type(args))
return sum(args)
print(add_all(1, 2, 3)) # (1, 2, 3) <class 'tuple'> -> 6
print(add_all(10, 20)) # (10, 20) <class 'tuple'> -> 30What **kwargs Does
The double asterisk before a parameter name packs every extra keyword argument into a dictionary called kwargs, where each key is the argument name and each value is what was passed in.
def print_profile(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
print_profile(name="Aarav", age=21, city="Pune")
# name: Aarav
# age: 21
# city: PunePacking vs Unpacking
Inside a function definition, * and ** pack incoming values together. But you can also use * and ** at call time to unpack an existing list, tuple or dictionary into separate arguments — the opposite operation.
def add(a, b, c):
return a + b + c
nums = [1, 2, 3]
print(add(*nums)) # unpacks list into a, b, c -> 6
info = {"a": 10, "b": 20, "c": 30}
print(add(**info)) # unpacks dict by matching keys -> 60Combining Both
You can accept regular parameters, *args and **kwargs all in one function, as long as you follow Python's argument order rules — regular parameters first, then *args, then **kwargs.
def order_summary(customer, *items, **details):
print(f"Customer: {customer}")
print(f"Items: {items}")
print(f"Details: {details}")
order_summary("Diya", "pen", "book", express=True, gift=False)When to Use Them
- Use *args when a function should accept a flexible number of positional values, like sum or max style helpers.
- Use **kwargs when a function should accept flexible, named settings or options, like configuration dictionaries.
- Use both together for wrapper or decorator functions that need to forward any arguments to another function.
Inside functools-based decorators, def wrapper(*args, **kwargs) is the standard way to accept and forward any arguments, no matter what the wrapped function expects.
