Sometimes you don't know in advance how many arguments a function needs to accept. Python solves this with two special parameter forms: *args, which collects any extra positional arguments into a tuple, and **kwargs, which collects any extra keyword arguments into a dictionary. The names args and kwargs are just convention — the single and double asterisks are what actually matter.
*args: Variable Positional Arguments
def total(*args):
print(f"args is a {type(args).__name__}: {args}")
return sum(args)
print(total(1, 2, 3))
print(total(10, 20, 30, 40))
Output:
args is a tuple: (1, 2, 3)
6
args is a tuple: (10, 20, 30, 40)
100
*args lets total() accept any number of positional arguments without you having to define a, b, c, d, ... ahead of time.
**kwargs: Variable Keyword Arguments
def describe(**kwargs):
print(f"kwargs is a {type(kwargs).__name__}: {kwargs}")
for key, value in kwargs.items():
print(f"{key}: {value}")
describe(name="Asha", age=21, course="Python")
Output:
kwargs is a dict: {'name': 'Asha', 'age': 21, 'course': 'Python'}
name: Asha
age: 21
course: Python
Combining Regular Parameters, *args, and **kwargs
All three can appear in the same function, but they must follow a strict order: regular parameters first, then *args, then **kwargs.
def build_profile(username, *args, **kwargs):
print(f"User: {username}")
print(f"Extra positional: {args}")
print(f"Extra keyword: {kwargs}")
build_profile("asha21", "admin", "verified", city="Mumbai", active=True)
Output:
User: asha21
Extra positional: ('admin', 'verified')
Extra keyword: {'city': 'Mumbai', 'active': True}
This pattern shows up constantly in real libraries — wrapper functions and decorators use *args, **kwargs so they can forward whatever arguments were passed to them, no matter the signature of the function underneath. For a complete worked example that puts this to use end to end, see our *args and **kwargs program.
