A Guide to Python *args and **kwargs

A practical guide to the special *args and **kwargs syntax in Python functions. Learn how to use them to accept a variable number of positional and keyword arguments.

When you start to explore more advanced Python functions and libraries, you will inevitably encounter the strange-looking *args and **kwargs parameters. These are not special keywords, but a special syntax that allows a function to accept a variable number of arguments.

Understanding how to use *args and **kwargs is key to writing more flexible and powerful functions in Python.

*args: Variable Positional Arguments

The *args syntax allows a function to accept any number of positional arguments. The name args is just a convention; you could call it *my_args or *numbers. The important part is the single asterisk *.

When you use *args in a function definition, Python collects all the extra positional arguments that are passed to the function into a tuple.

Let's look at a function that can sum an arbitrary number of numbers:

def sum_all(*args):
    print(f"The args are: {args}")
    total = 0
    for num in args:
        total += num
    return total

# Call the function with different numbers of arguments
print(sum_all(1, 2, 3))       # Output: 6
print(sum_all(10, 20, 30, 40)) # Output: 100

Inside the sum_all function, args will be a tuple containing all the numbers that were passed in (e.g., (1, 2, 3)).

**kwargs: Variable Keyword Arguments

The **kwargs syntax is similar, but it's for keyword arguments. The double asterisk ** tells Python to collect all the extra keyword arguments (arguments passed with a name, like name="Alice") into a dictionary.

def display_info(**kwargs):
    print(f"The kwargs are: {kwargs}")
    for key, value in kwargs.items():
        print(f"{key}: {value}")

display_info(name="Alice", age=30, city="New York")

Output:

The kwargs are: {'name': 'Alice', 'age': 30, 'city': 'New York'}
name: Alice
age: 30
city: New York

Inside the display_info function, kwargs is a dictionary where the keys are the argument names and the values are the argument values.

Combining Them in a Function Signature

You can combine *args and **kwargs with standard arguments in a single function. The required order is:

  1. Standard arguments
  2. *args
  3. **kwargs
def my_function(a, b, *args, **kwargs):
    print(f"a = {a}")
    print(f"b = {b}")
    print(f"args = {args}")
    print(f"kwargs = {kwargs}")

my_function(1, 2, 3, 4, 5, name="Alice", city="London")

Output:

a = 1
b = 2
args = (3, 4, 5)
kwargs = {'name': 'Alice', 'city': 'London'}

Unpacking with * and **

You can also use the * and ** operators when you are calling a function. This is known as unpacking.

  • The * operator will unpack a list or tuple into positional arguments.
  • The ** operator will unpack a dictionary into keyword arguments.
def add(a, b, c):
    return a + b + c

# A list of numbers
my_list = [10, 20, 30]

# Unpack the list into positional arguments
result = add(*my_list) # This is equivalent to calling add(10, 20, 30)
print(result) # 60


def display(name, age):
    print(f"Name: {name}, Age: {age}")

# A dictionary of info
my_dict = {'name': 'Bob', 'age': 40}

# Unpack the dictionary into keyword arguments
display(**my_dict) # This is equivalent to calling display(name='Bob', age=40)

Why Are They Useful?

  • Flexibility: They allow you to write functions that can handle a variable number of inputs, making your code more flexible.
  • Function Decorators: They are used extensively in function decorators, where you need to write a wrapper that can accept any arguments and pass them on to the original function.
  • Inheritance: They are useful for subclassing and passing arguments up to a parent class's __init__ method.

Conclusion

*args and **kwargs are powerful features in Python that provide a lot of flexibility when defining and calling functions. While the syntax might look a bit strange at first, it's a fundamental concept that enables many of the advanced patterns you'll see in popular Python libraries and frameworks. By understanding how to use them to handle variable arguments and to unpack collections, you can write more adaptable and powerful Python code.