How to combine *args and **kwargs in Python function calls?

PythonPythonBeginner
Practice Now

Introduction

Python's *args and **kwargs are powerful features that allow you to write more flexible and dynamic functions. In this tutorial, we'll explore how to combine these two techniques to create versatile function calls that can handle a variable number of arguments and keyword arguments. By the end, you'll have a solid understanding of how to leverage *args and **kwargs to write more robust and adaptable Python code.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL python(("`Python`")) -.-> python/FunctionsGroup(["`Functions`"]) python/FunctionsGroup -.-> python/keyword_arguments("`Keyword Arguments`") python/FunctionsGroup -.-> python/function_definition("`Function Definition`") python/FunctionsGroup -.-> python/arguments_return("`Arguments and Return Values`") python/FunctionsGroup -.-> python/default_arguments("`Default Arguments`") python/FunctionsGroup -.-> python/lambda_functions("`Lambda Functions`") subgraph Lab Skills python/keyword_arguments -.-> lab-417958{{"`How to combine *args and **kwargs in Python function calls?`"}} python/function_definition -.-> lab-417958{{"`How to combine *args and **kwargs in Python function calls?`"}} python/arguments_return -.-> lab-417958{{"`How to combine *args and **kwargs in Python function calls?`"}} python/default_arguments -.-> lab-417958{{"`How to combine *args and **kwargs in Python function calls?`"}} python/lambda_functions -.-> lab-417958{{"`How to combine *args and **kwargs in Python function calls?`"}} end

Understanding *args and **kwargs

What are *args and **kwargs?

In Python, *args and **kwargs are special syntax used in function definitions to handle a variable number of arguments. They allow functions to accept an arbitrary number of positional arguments (*args) and/or keyword arguments (**kwargs).

*args (Non-Keyword Arguments)

The *args syntax allows a function to accept any number of positional arguments. These arguments are then packed into a tuple that can be iterated over within the function. This is useful when you don't know in advance how many arguments the function will receive.

def print_numbers(*args):
    for arg in args:
        print(arg)

print_numbers(1, 2, 3)  ## Output: 1 2 3
print_numbers(4, 5, 6, 7, 8)  ## Output: 4 5 6 7 8

**kwargs (Keyword Arguments)

The **kwargs syntax allows a function to accept any number of keyword arguments. These arguments are then packed into a dictionary, where the keys are the argument names and the values are the corresponding argument values. This is useful when you want to pass an arbitrary number of named parameters to a function.

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

print_info(name="LabEx", age=30, city="New York")
## Output:
## name: LabEx
## age: 30
## city: New York

Combining *args and **kwargs

You can use both *args and **kwargs in the same function definition. The *args will collect all the positional arguments, while the **kwargs will collect all the keyword arguments.

def print_all(*args, **kwargs):
    for arg in args:
        print(arg)
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_all(1, 2, 3, name="LabEx", age=30)
## Output:
## 1
## 2
## 3
## name: LabEx
## age: 30

In this example, the function print_all() can accept any number of positional arguments (*args) and any number of keyword arguments (**kwargs).

Using *args and **kwargs in Function Calls

Passing *args to a Function

To pass a variable number of positional arguments to a function that accepts *args, you can simply unpack the arguments using the * operator.

def print_numbers(*args):
    for arg in args:
        print(arg)

numbers = [1, 2, 3, 4, 5]
print_numbers(*numbers)
## Output:
## 1
## 2
## 3
## 4
## 5

In this example, the *numbers expression unpacks the elements of the numbers list and passes them as individual arguments to the print_numbers() function.

Passing **kwargs to a Function

To pass a variable number of keyword arguments to a function that accepts **kwargs, you can use the ** operator to unpack a dictionary into keyword arguments.

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

info = {"name": "LabEx", "age": 30, "city": "New York"}
print_info(**info)
## Output:
## name: LabEx
## age: 30
## city: New York

In this example, the **info expression unpacks the key-value pairs of the info dictionary and passes them as individual keyword arguments to the print_info() function.

Combining *args and **kwargs in Function Calls

You can also combine *args and **kwargs in the same function call. The *args will collect all the positional arguments, while the **kwargs will collect all the keyword arguments.

def print_all(*args, **kwargs):
    for arg in args:
        print(arg)
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_all(1, 2, 3, name="LabEx", age=30)
## Output:
## 1
## 2
## 3
## name: LabEx
## age: 30

In this example, the 1, 2, and 3 are passed as positional arguments to the *args, while the name and age are passed as keyword arguments to the **kwargs.

Practical Examples of *args and **kwargs

Variadic Function for Arithmetic Operations

Let's create a function that can perform various arithmetic operations on any number of arguments.

def arithmetic_operations(*args, operator='+'):
    result = args[0]
    for i in range(1, len(args)):
        if operator == '+':
            result += args[i]
        elif operator == '-':
            result -= args[i]
        elif operator == '*':
            result *= args[i]
        elif operator == '/':
            result /= args[i]
    return result

print(arithmetic_operations(1, 2, 3, 4, operator='+'))  ## Output: 10
print(arithmetic_operations(10, 3, 2, operator='-'))  ## Output: 5
print(arithmetic_operations(2, 3, 4, operator='*'))  ## Output: 24
print(arithmetic_operations(20, 4, operator='/'))  ## Output: 5.0

In this example, the arithmetic_operations() function can accept any number of arguments using *args, and the desired arithmetic operation is specified using the operator keyword argument.

Collecting User Input with *args

Suppose you want to create a function that collects an arbitrary number of user inputs and stores them in a list.

def collect_inputs(*args):
    user_inputs = []
    for arg in args:
        user_input = input(f"Enter {arg}: ")
        user_inputs.append(user_input)
    return user_inputs

names = collect_inputs("name", "age", "city")
print(names)
## Output:
## Enter name: LabEx
## Enter age: 30
## Enter city: New York
## ['LabEx', '30', 'New York']

In this example, the collect_inputs() function uses *args to accept an arbitrary number of prompts, and then collects the user's responses and stores them in a list.

Logging Function with **kwargs

Imagine you want to create a logging function that can log messages with different levels (e.g., debug, info, warning, error) and include additional metadata.

def log_message(**kwargs):
    log_level = kwargs.get('level', 'info')
    message = kwargs['message']
    metadata = kwargs.get('metadata', {})

    print(f"[{log_level.upper()}] {message}")
    for key, value in metadata.items():
        print(f"  {key}: {value}")

log_message(level='debug', message='This is a debug message')
## Output:
## [DEBUG] This is a debug message

log_message(level='warning', message='Something unusual happened', metadata={'user': 'LabEx', 'timestamp': '2023-04-18 12:34:56'})
## Output:
## [WARNING] Something unusual happened
##   user: LabEx
##   timestamp: 2023-04-18 12:34:56

In this example, the log_message() function uses **kwargs to accept an arbitrary number of keyword arguments, including the log level, message, and optional metadata.

Summary

In this Python tutorial, you've learned how to effectively combine *args and **kwargs to create flexible and dynamic function calls. By understanding the differences between these two techniques and how to use them together, you can write more powerful and adaptable Python functions that can handle a wide range of input scenarios. This knowledge will help you write more efficient and maintainable code, making you a more proficient Python programmer.

Other Python Tutorials you may like