
Understanding *args
and **kwargs
is a vital skill for any Python developer aiming to write clean, flexible, and scalable code. These special syntax constructs allow a function to accept an arbitrary number of arguments, enabling developers to build dynamic APIs, reusable decorators, and adaptable function interfaces.
In this guide, we will explore both basic and advanced use cases of *args
and **kwargs
, including their internal behavior, best practices, and real-world examples.
What are *args
and **kwargs
?
*args
allows you to handle arbitrary numbers of positional arguments in a function.**kwargs
allows you to handle arbitrary numbers of keyword arguments in a function.
These constructs are especially useful when:
- You don’t know in advance how many arguments a function might receive.
- You want to forward arguments from one function to another.
- You are writing decorator functions.
- You need to process optional configuration parameters or user inputs flexibly.
Syntax Overview
def function_name(*args, **kwargs):
pass
*args
collects extra positional arguments into a tuple.**kwargs
collects extra keyword arguments into a dictionary.
Detailed Example with *args
def calculate_total(*args):
print(f"Received arguments: {args}")
return sum(args)
total = calculate_total(10, 20, 30)
print("Total:", total)
Behavior:
args
is a tuple:(10, 20, 30)
- Useful when accepting a list of numeric values, coordinates, or ordered parameters.
More Use Cases:
- Variable-length mathematical operations.
- Logging functions that accept a variable number of messages.
- Aggregating statistics across multiple arguments.
Detailed Example with **kwargs
def create_profile(**kwargs):
print("Profile Data:")
for key, value in kwargs.items():
print(f"{key} = {value}")
create_profile(name="Alice", age=28, country="USA")
Behavior:
kwargs
is a dictionary:{'name': 'Alice', 'age': 28, 'country': 'USA'}
- Enables passing any number of named parameters.
More Use Cases:
- Dynamic configuration or metadata.
- API clients accepting arbitrary request parameters.
- Form data handling.
Using *args
and **kwargs
Together
def log_event(event_type, *args, **kwargs):
print("Event Type:", event_type)
print("Args:", args)
print("Kwargs:", kwargs)
log_event("ERROR", "File not found", code=404, path="/home/data.txt")
Order Rule:
- You must follow this order when defining function parameters:
- Regular positional arguments
*args
- Keyword-only arguments (if any)
**kwargs
def func(pos1, *args, kw1=None, **kwargs):
pass
Unpacking *args
and **kwargs
in Function Calls
Unpacking with *args
:
def multiply(a, b, c):
return a * b * c
nums = (2, 3, 4)
result = multiply(*nums)
Unpacking with **kwargs
:
def greet(name, message):
return f"{message}, {name}"
data = {'name': 'John', 'message': 'Good morning'}
print(greet(**data))
Use Case:
- Forwarding arguments from wrapper functions.
- Unpacking stored arguments when calling a function programmatically.
- Dynamically invoking functions from JSON or dictionaries.
Real-World Use Cases
1. Writing Decorators
def logger(func):
def wrapper(*args, **kwargs):
print("Function called with:")
print("Arguments:", args)
print("Keyword Arguments:", kwargs)
return func(*args, **kwargs)
return wrapper
@logger
def process_data(a, b):
return a + b
process_data(5, b=10)
2. Argument Forwarding
def connect(host, port, **options):
print(f"Connecting to {host}:{port}")
print("Options:", options)
def setup_connection(*args, **kwargs):
connect(*args, **kwargs)
setup_connection("localhost", 8080, timeout=60, ssl=True)
3. Building Flexible APIs
def configure_settings(**kwargs):
defaults = {
'theme': 'light',
'debug': False,
'timeout': 30
}
defaults.update(kwargs)
return defaults
settings = configure_settings(debug=True, timeout=60)
print(settings)
Best Practices
- Use
*args
and**kwargs
only when needed
Avoid overusing them as they can reduce code readability. Use them when your function truly benefits from variable input lengths. - Document expected keys in
kwargs
Since**kwargs
accepts any keyword argument, make sure to document expected values to avoid silent failures. - Validate inputs inside the function
Check for required parameters or types when using**kwargs
to prevent misconfigurations. - Use keyword-only arguments for clarity
If your function already takes*args
, you can define named parameters that must be passed using keywords. pythonCopyEditdef func(*args, required_param=None, **kwargs): if required_param is None: raise ValueError("required_param is mandatory")
- Use type hints for better tooling support and code clarity: pythonCopyEdit
def collect_data(*args: int, **kwargs: str) -> None: pass
- Be mindful when chaining function calls
When forwarding arguments, be careful not to pass duplicates for the same parameter via bothargs
andkwargs
.
Limitations and Common Pitfalls
- Loss of explicitness: When overused, it becomes unclear what arguments the function is designed to accept.
- Error masking: If you silently consume unexpected arguments using
**kwargs
, you might miss logical bugs. - Conflict in argument names: Always ensure arguments passed via
*args
and**kwargs
don’t conflict with explicitly named parameters.
Summary Table
Feature | *args | **kwargs |
---|---|---|
Accepts | Positional arguments | Keyword arguments |
Internally Stored As | Tuple | Dictionary |
Access Pattern | for arg in args: | for key, value in kwargs.items(): |
Typical Use Cases | Variable-length input, wrappers | Config data, decorators, forwarding |
Unpacked With | *tuple_variable | **dict_variable |
Final Thoughts
Mastering *args
and **kwargs
unlocks a higher level of Python proficiency. They make your codebase more extensible, reusable, and cleaner when used appropriately. Whether you’re developing decorators, constructing APIs, or dynamically invoking functions, these features offer the flexibility needed for modern Python development.
However, with great power comes responsibility—overuse or misuse can quickly turn your code into an unmaintainable mess. Always prefer explicit parameters when possible, and resort to *args
and **kwargs
when your use case genuinely demands flexibility.

I’m Shreyash Mhashilkar, an IT professional who loves building user-friendly, scalable digital solutions. Outside of coding, I enjoy researching new places, learning about different cultures, and exploring how technology shapes the way we live and travel. I share my experiences and discoveries to help others explore new places, cultures, and ideas with curiosity and enthusiasm.