What do *args and **kwargs mean in Python function definitions?
In Python, what is the purpose of the * (single asterisk) and ** (double asterisk) syntax when used in function parameters? Explain their behavior with these examples:
def foo(x, y, *args):
pass
def bar(x, y, **kwargs):
pass
For information about how these syntaxes work in function calls, see: What do ** (double star/asterisk) and * (star/asterisk) mean in a function call?
In Python, *args and **kwargs are special syntax elements that allow functions to accept a variable number of arguments. *args collects any number of positional (non-keyword) arguments into a tuple, while **kwargs collects any number of keyword arguments into a dictionary. These provide flexibility in function definitions, allowing you to create more versatile and adaptable functions without specifying exact parameter counts.
Contents
- What Are *args and **kwargs?
- Function Definition Syntax Rules
- Behavior of *args in Functions
- Behavior of **kwargs in Functions
- Common Use Cases
- Error Handling and Best Practices
What Are *args and **kwargs?
*args is a special syntax in Python that allows a function to accept any number of positional (non-keyword) arguments. When you see *args in a function definition, it means you can pass as many values as you want when calling that function[^1]. Inside the function, these arguments are accessible as a tuple[^2].
**kwargs is a special syntax that allows a function to accept any number of keyword arguments. As Mozilla Developer Network explains, **kwargs provides flexibility to use keyword arguments in your program[^3]. Inside the function, these arguments are accessible as a dictionary[^4].
The names args and kwargs are conventional but not required - you could technically use *my_args or **my_kwargs, though the standard names are widely recognized and recommended for readability.
Function Definition Syntax Rules
When defining functions with *args and **kwargs, there are important syntax rules you must follow:
-
Parameter Order: Regular parameters must come before *args, and *args must come before **kwargs. The correct order is:
pythondef function_name(normal_param1, normal_param2, *args, **kwargs): pass -
*args Position: *args can only appear once in a function definition and must come after any regular parameters but before **kwargs.
-
**kwargs Position: **kwargs can only appear once in a function definition and must come after *args if both are present.
As Real Python demonstrates, if you try to put **kwargs before *args, you’ll get a SyntaxError[^5]:
# This will cause a SyntaxError!
def my_function(a, b, **kwargs, *args):
pass
Behavior of *args in Functions
When you use *args in a function definition, the arguments passed to the function are collected into a tuple. As Programiz explains, “The arguments are passed as a tuple and these passed arguments make tuple inside the function with same name as the parameter excluding asterisk *”[^6].
Consider this example with your foo function:
def foo(x, y, *args):
print(f"x: {x}")
print(f"y: {y}")
print(f"args: {args}")
print(f"type of args: {type(args)}")
# Function calls
foo(1, 2) # args will be empty tuple
foo(1, 2, 3, 4, 5) # args will be (3, 4, 5)
foo(1, 2, 'a', 'b', 'c', True, None) # args will be ('a', 'b', 'c', True, None)
Output:
x: 1
y: 2
args: ()
type of args: <class 'tuple'>
x: 1
y: 2
args: (3, 4, 5)
type of args: <class 'tuple'>
x: 1
y: 2
args: ('a', 'b', 'c', True, None)
type of args: <class 'tuple'>
As shown from the Stack Overflow example, when only positional arguments are passed, args contains those values while kwargs is empty[^7]:
def example_func(*args, **kwargs):
print(f"args: {args}")
print(f"kwargs: {kwargs}")
example_func(1, 2)
# Output:
# args: (1, 2)
# kwargs: {}
Behavior of **kwargs in Functions
When you use **kwargs in a function definition, the keyword arguments passed to the function are collected into a dictionary. As note.nkmk.me shows, def func_kwargs(**kwargs): print('kwargs: ', kwargs) print('type: ', type(kwargs)) will display kwargs as a dictionary[^8].
Consider this example with your bar function:
def bar(x, y, **kwargs):
print(f"x: {x}")
print(f"y: {y}")
print(f"kwargs: {kwargs}")
print(f"type of kwargs: {type(kwargs)}")
# Function calls
bar(1, 2) # kwargs will be empty dict
bar(1, 2, name='Alice', age=25, city='New York') # kwargs will be {'name': 'Alice', 'age': 25, 'city': 'New York'}
Output:
x: 1
y: 2
kwargs: {}
type of kwargs: <class 'dict'>
x: 1
y: 2
kwargs: {'name': 'Alice', 'age': 25, 'city': 'New York'}
type of kwargs: <class 'dict'>
From the Stack Overflow example, when keyword arguments are passed, kwargs contains those key-value pairs while args is empty[^7]:
def example_func(*args, **kwargs):
print(f"args: {args}")
print(f"kwargs: {kwargs}")
example_func(a=1, b=2)
# Output:
# args: ()
# kwargs: {'a': 1, 'b': 2}
You can access individual keyword arguments using dictionary methods:
def show_info(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
show_info(name="John", age=30, email="john@example.com")
# Output:
# name: John
# age: 30
# email: john@example.com
Common Use Cases
Flexible Function Parameters
*args and **kwargs are commonly used to create functions that can handle various numbers and types of arguments. As GeeksforGeeks states, “*args allows us to pass any number of positional (non-keyword) arguments to a function”[^2].
Function Wrappers and Decorators
These syntaxes are frequently used in decorators and wrapper functions that need to accept and pass through arbitrary arguments to the wrapped function:
def decorator(func):
def wrapper(*args, **kwargs):
print("Before function call")
result = func(*args, **kwargs)
print("After function call")
return result
return wrapper
@decorator
def greet(name, greeting="Hello"):
return f"{greeting}, {name}!"
print(greet("Alice", greeting="Hi"))
Creating Flexible APIs
*args and **kwargs allow you to create more flexible APIs that can accommodate different use cases without breaking existing code[^3].
Combining with Regular Parameters
You can mix regular parameters with *args and **kwargs for more complex function signatures:
def process_data(data, *options, **settings):
print(f"Processing: {data}")
print(f"Options: {options}")
print(f"Settings: {settings}")
process_data([1, 2, 3], 'verbose', 'fast', method='quicksort', debug=True)
Practical Example: Flexible String Concatenation
As shown in the Real Python example, you can create a function that uses **kwargs to concatenate strings with different separators[^1]:
def concatenate(**kwargs):
result = ""
# Iterating over the Python kwargs dictionary
for arg in kwargs.values():
result += arg
return result
print(concatenate(a="Real", b="Python", c="Is", d="Great", e="!"))
# Output: RealPythonIsGreat!
Error Handling and Best Practices
Common Errors
-
Invalid Syntax: Putting **kwargs before *args in function definitions:
python# This causes SyntaxError: invalid syntax def invalid_func(x, y, **kwargs, *args): pass -
Positional-Keyword Confusion: Trying to use *args for keyword arguments or vice versa.
Best Practices
-
Use Meaningful Names: While
argsandkwargsare conventional, consider more descriptive names when appropriate for better readability. -
Document Your Functions: When using *args and **kwargs, provide clear documentation about what types of arguments are expected.
-
Validate Arguments: Consider adding validation logic inside functions that use *args and **kwargs to ensure they receive expected argument types.
-
Use Sparingly: While flexible, overusing *args and **kwargs can make code harder to understand. Use them only when the flexibility is genuinely needed.
When to Use Each
- *Use args when you need to accept multiple positional arguments of the same type
- **Use kwargs when you need to accept named parameters or configuration options
- Use both when you need maximum flexibility in accepting arguments
Conclusion
*args and **kwargs are powerful Python syntax elements that provide flexibility in function definitions. *args collects positional arguments into a tuple, while **kwargs collects keyword arguments into a dictionary. Understanding their proper usage, syntax rules, and behavior patterns is essential for writing flexible and maintainable Python code.
Key takeaways:
- *args must come before **kwargs in function parameter definitions
- *args creates a tuple of all extra positional arguments
- **kwargs creates a dictionary of all extra keyword arguments
- These syntaxes are particularly useful for decorators, wrappers, and creating flexible APIs
- Proper parameter ordering is crucial to avoid syntax errors
By mastering *args and **kwargs, you can create more versatile functions that handle various argument patterns while maintaining clean, readable code.
Sources
- Python args and kwargs: Demystified – Real Python
- *args and **kwargs in Python - GeeksforGeeks
- How To Use *args and **kwargs in Python 3 | DigitalOcean
- *args and **kwargs in Python (Variable-Length Arguments) | note.nkmk.me
- Python *args and **kwargs (With Examples) | Programiz
- What are args and kwargs and when to use them | Python For The Lab
- python - What is the purpose and use of **kwargs? - Stack Overflow
- 10 Examples to Master *args and **kwargs in Python | Towards Data Science