6 min read
ā¢Question 23 of 41medium*args and **kwargs
Variable-length arguments in Python.
What You'll Learn
- What *args and **kwargs are
- When and how to use them
- Function parameter ordering rules
- Unpacking arguments when calling functions
- Real-world use cases
Understanding *args
*args allows a function to accept any number of positional arguments. Inside the function, args is a tuple.
code.pyPython
def sum_all(*args):
print(f"args is a tuple: {type(args)}") # <class 'tuple'>
print(f"Received: {args}")
return sum(args)
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all()) # 0 (empty tuple)
# Iterate over args
def print_numbered(*args):
for i, arg in enumerate(args, 1):
print(f"{i}. {arg}")
print_numbered("apple", "banana", "cherry")
# 1. apple
# 2. banana
# 3. cherryUnderstanding **kwargs
**kwargs allows a function to accept any number of keyword arguments. Inside the function, kwargs is a dictionary.
code.pyPython
def print_info(**kwargs):
print(f"kwargs is a dict: {type(kwargs)}") # <class 'dict'>
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=30, city="NYC")
# name: Alice
# age: 30
# city: NYC
# With default handling
def create_user(**kwargs):
return {
"name": kwargs.get("name", "Anonymous"),
"role": kwargs.get("role", "user"),
"active": kwargs.get("active", True)
}
user = create_user(name="Bob", role="admin")
print(user) # {'name': 'Bob', 'role': 'admin', 'active': True}Parameter Order Rules
Python requires parameters in this specific order:
code.pyPython
def func(
positional, # 1. Regular positional
*args, # 2. *args
keyword_only, # 3. Keyword-only (after *)
**kwargs # 4. **kwargs (always last)
):
pass
# Complete example
def example(a, b, *args, option=True, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}")
print(f"option={option}")
print(f"kwargs={kwargs}")
example(1, 2, 3, 4, option=False, x=10, y=20)
# a=1, b=2
# args=(3, 4)
# option=False
# kwargs={'x': 10, 'y': 20}Unpacking Arguments
Use * and ** when calling functions to unpack sequences and dictionaries:
code.pyPython
def greet(name, greeting, punctuation):
return f"{greeting}, {name}{punctuation}"
# Unpack list/tuple with *
args = ["Alice", "Hello", "!"]
print(greet(*args)) # "Hello, Alice!"
# Unpack dict with **
kwargs = {"name": "Bob", "greeting": "Hi", "punctuation": "?"}
print(greet(**kwargs)) # "Hi, Bob?"
# Combine both
data = ["Charlie"]
options = {"greeting": "Hey", "punctuation": "."}
print(greet(*data, **options)) # "Hey, Charlie."Forwarding Arguments
A common pattern for wrapper functions:
code.pyPython
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
print(f" args: {args}")
print(f" kwargs: {kwargs}")
return func(*args, **kwargs) # Forward all arguments
return wrapper
@log_call
def calculate(a, b, operation="add"):
if operation == "add":
return a + b
return a - b
calculate(5, 3, operation="subtract")
# Calling calculate
# args: (5, 3)
# kwargs: {'operation': 'subtract'}
# Returns: 2Practical Use Cases
code.pyPython
# 1. Flexible initialization
class Config:
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
config = Config(debug=True, host="localhost", port=8080)
print(config.debug) # True
# 2. Merging dictionaries
def merge_dicts(*dicts):
result = {}
for d in dicts:
result.update(d)
return result
combined = merge_dicts({"a": 1}, {"b": 2}, {"c": 3})
print(combined) # {'a': 1, 'b': 2, 'c': 3}
# 3. String formatting
template = "Name: {name}, Age: {age}"
data = {"name": "Alice", "age": 30}
print(template.format(**data)) # "Name: Alice, Age: 30"Interview Tip
When asked about *args and **kwargs:
- *args ā tuple of positional arguments
- **kwargs ā dict of keyword arguments
- Order: positional, *args, keyword-only, **kwargs
- Use * and ** for unpacking when calling functions
- Common in decorators and wrapper functions