A parameter prefixed with a double asterisk gathers every keyword argument the caller passes that doesn't match a named parameter, collecting them into a dict keyed by argument name — again, kwargs is just a conventional name. This is how functions can accept flexible, optional configuration without listing every possible option explicitly, and it's often paired with *args to build fully generic wrapper functions and decorators. At a call site, the double asterisk unpacks an existing dict into separate keyword arguments.
1Understanding Keyword Arguments (**kwargs)
A parameter prefixed with a double asterisk gathers every keyword argument the caller passes that doesn't match a named parameter, collecting them into a dict keyed by argument name — again, kwargs is just a conventional name. This is how functions can accept flexible, optional configuration without listing every possible option explicitly, and it's often paired with *args to build fully generic wrapper functions and decorators. At a call site, the double asterisk unpacks an existing dict into separate keyword arguments.
Use a double asterisk at a call site to spread an existing dictionary out into keyword arguments — the mirror image of collecting them with **kwargs in a function definition, and a common pattern for forwarding configuration through a chain of function calls.
def describe(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
describe(name="Alice", age=30)2Practical Example
Here is a real-world application of Keyword Arguments (kwargs)** showing how it is used in production Python code.
def build_url(base, **params):
query = "&".join(f"{k}={v}" for k, v in params.items())
return f"{base}?{query}"
print(build_url("/search", q="python", page=2))3Best Practices
Follow these guidelines when working with Keyword Arguments (kwargs)**:
1. Use **kwargs when a function needs to accept flexible, optional named configuration it doesn't fully know in advance
2. Prefer explicit named parameters with defaults over **kwargs when the accepted options are actually fixed and known
3. Combine *args and **kwargs in wrapper functions/decorators to forward arbitrary arguments through to the wrapped function unchanged
Tip: Use a double asterisk at a call site to spread an existing dictionary out into keyword arguments — the mirror image of collecting them with **kwargs in a function definition, and a common pattern for forwarding configuration through a chain of function calls.
def describe(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
describe(name="Alice", age=30)