NeuroAgent

Complete Guide to *args and **kwargs in Python

Learn how *args and **kwargs work in Python function definitions. Discover how these syntax elements collect positional arguments into tuples and keyword arguments into dictionaries for flexible function design.

Question

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:

python
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?

NeuroAgent

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?

*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:

  1. Parameter Order: Regular parameters must come before *args, and *args must come before **kwargs. The correct order is:

    python
    def function_name(normal_param1, normal_param2, *args, **kwargs):
        pass
    
  2. *args Position: *args can only appear once in a function definition and must come after any regular parameters but before **kwargs.

  3. **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]:

python
# 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:

python
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]:

python
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:

python
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]:

python
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:

python
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:

python
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:

python
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]:

python
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

  1. Invalid Syntax: Putting **kwargs before *args in function definitions:

    python
    # This causes SyntaxError: invalid syntax
    def invalid_func(x, y, **kwargs, *args):
        pass
    
  2. Positional-Keyword Confusion: Trying to use *args for keyword arguments or vice versa.

Best Practices

  1. Use Meaningful Names: While args and kwargs are conventional, consider more descriptive names when appropriate for better readability.

  2. Document Your Functions: When using *args and **kwargs, provide clear documentation about what types of arguments are expected.

  3. Validate Arguments: Consider adding validation logic inside functions that use *args and **kwargs to ensure they receive expected argument types.

  4. 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

  1. Python args and kwargs: Demystified – Real Python
  2. *args and **kwargs in Python - GeeksforGeeks
  3. How To Use *args and **kwargs in Python 3 | DigitalOcean
  4. *args and **kwargs in Python (Variable-Length Arguments) | note.nkmk.me
  5. Python *args and **kwargs (With Examples) | Programiz
  6. What are args and kwargs and when to use them | Python For The Lab
  7. python - What is the purpose and use of **kwargs? - Stack Overflow
  8. 10 Examples to Master *args and **kwargs in Python | Towards Data Science