🐶
Python

Python *args and **kwargs Explained

By Filip on 10/05/2024

Learn how single * and double ** asterisks unpack iterables and dictionaries, offering flexibility when passing arguments to functions in Python.

Python *args and **kwargs Explained

Table of Contents

Introduction

In Python, you can use single and double asterisks (* and ) to handle a flexible number of arguments in your functions. The single asterisk (*) is used to gather an arbitrary number of positional arguments, while the double asterisk () is used to gather keyword arguments.

Step-by-Step Guide

In Python, single and double asterisks have special meanings when used with function parameters. Let's break down how they work:

Single Asterisk (*): Gathering Positional Arguments

  1. Imagine you want a function that can accept any number of arguments.
  2. Placing a single asterisk (*) before a parameter name in a function definition tells Python to pack all the arguments passed to the function (beyond any regular parameters) into a tuple.
  3. Inside the function, you can access and work with these arguments as a tuple.

Example:

def my_function(arg1, *args):
    print("Regular argument:", arg1)
    for arg in args:
        print("Additional argument:", arg)

my_function(1, 2, 3, 4)

Double Asterisk (): Gathering Keyword Arguments**

  1. Similar to the single asterisk, but for keyword arguments (arguments passed with names like name="Alice").
  2. Using a double asterisk (**) before a parameter name in a function definition creates a dictionary.
  3. Python takes all keyword arguments passed to the function and puts them into this dictionary, with the argument names as keys and their values as the corresponding dictionary values.

Example:

def greet_person(name, **kwargs):
    print(f"Hello {name}!")
    if kwargs:
        print("Here's some additional information:")
        for key, value in kwargs.items():
            print(f"- {key}: {value}")

greet_person("Bob", age=30, city="New York")

Key Points:

  • You can use both *args and **kwargs in the same function definition to handle a mix of positional and keyword arguments.
  • The names args and kwargs are conventions, you can use other names, but sticking to these makes your code more readable.

Let me know if you'd like to see more advanced examples or have any other Python questions!

Code Example

The code provides examples of using *args and **kwargs in Python functions to handle a flexible number of arguments. It shows how *args captures positional arguments into a tuple, **kwargs captures keyword arguments into a dictionary, and how to use both in a single function. The examples include calculating a sum with variable numbers of inputs, building user profiles with different attributes, and a versatile function demonstrating the combined usage of *args and **kwargs.

Here are the code examples illustrating the use of *args and **kwargs in Python functions:

*1. Gathering Positional Arguments with args:

def calculate_sum(arg1, *args):
  """Calculates the sum of all arguments.

  Args:
    arg1: The first argument.
    *args: Any number of additional arguments.

  Returns:
    The sum of all arguments.
  """
  total = arg1
  for arg in args:
    total += arg
  return total

print(calculate_sum(1, 2, 3))  # Output: 6
print(calculate_sum(5, 10, 15, 20))  # Output: 50
print(calculate_sum(10))  # Output: 10 (only arg1 provided)

**2. Gathering Keyword Arguments with kwargs:

def build_profile(name, **kwargs):
  """Builds a user profile dictionary.

  Args:
    name: The user's name.
    **kwargs: Any number of keyword arguments representing profile information.

  Returns:
    A dictionary containing the user's profile.
  """
  profile = {"name": name}
  for key, value in kwargs.items():
    profile[key] = value
  return profile

user_profile = build_profile("Alice", age=25, city="London", occupation="Engineer")
print(user_profile)  
# Output: {'name': 'Alice', 'age': 25, 'city': 'London', 'occupation': 'Engineer'}

another_profile = build_profile("Bob", country="USA")
print(another_profile)  
# Output: {'name': 'Bob', 'country': 'USA'}

**3. Combining *args and kwargs:

def versatile_function(arg1, *args, **kwargs):
  """Demonstrates using both *args and **kwargs.

  Args:
    arg1: The first argument.
    *args: Any number of additional positional arguments.
    **kwargs: Any number of keyword arguments.
  """
  print("Regular argument:", arg1)
  print("Additional arguments (tuple):", args)
  print("Keyword arguments (dictionary):", kwargs)

versatile_function(10, 20, 30, name="John", city="Paris")
# Output:
# Regular argument: 10
# Additional arguments (tuple): (20, 30)
# Keyword arguments (dictionary): {'name': 'John', 'city': 'Paris'}

These examples demonstrate how *args and **kwargs provide flexibility in function definitions, allowing them to handle a variable number of arguments in different ways. Remember that *args collects extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary.

Additional Notes

Here are some additional points to deepen your understanding:

Flexibility and Reusability:

  • *args and **kwargs make your functions more flexible by allowing them to accept a varying number of arguments. This is particularly useful when you don't know in advance how many arguments will be passed.
  • This flexibility enhances code reusability. You can write a single function that can handle different input scenarios without needing to create multiple versions.

Order Matters:

  • When defining function parameters, the order is crucial: regular parameters, then *args, and finally **kwargs.
  • This order ensures that Python can correctly interpret the arguments being passed.

Unpacking Iterables:

  • You can use * and ** outside of function definitions to unpack iterables (like lists, tuples) and dictionaries, respectively.
  • Example:
    my_list = [1, 2, 3]
    print(*my_list)  # Output: 1 2 3
    
    my_dict = {'a': 1, 'b': 2}
    print(**my_dict)  # Equivalent to print(a=1, b=2) 

Common Use Cases:

  • Decorators: *args and **kwargs are frequently used in decorators, allowing them to work with functions that have different argument signatures.
  • Forwarding Arguments: You can use these techniques to pass arguments from one function to another, especially when working with nested functions or callbacks.

Readability vs. Magic:

  • While powerful, overuse of *args and **kwargs can sometimes harm code readability. It's generally good practice to use them when necessary for flexibility, but to be mindful of making your function signatures clear and understandable.

Summary

Feature Single Asterisk (*args) Double Asterisk (**kwargs)
Purpose Gathers positional arguments Gathers keyword arguments
Data Structure Packs arguments into a tuple Packs arguments into a dictionary
Example Usage def my_function(arg1, *args): def greet_person(name, **kwargs):
Accessing Arguments Iterate through the tuple: for arg in args: Access values by key: kwargs['age'] or iterate through key-value pairs: for key, value in kwargs.items():

Key Points:

  • Both *args and **kwargs provide flexibility by allowing functions to accept a variable number of arguments.
  • args and kwargs are conventional names, but you can use other names.
  • You can use both *args and **kwargs in the same function definition.

Conclusion

Understanding how to use *args and **kwargs provides a powerful way to create more flexible and reusable functions in Python. These concepts are essential for writing Pythonic code that can adapt to various input scenarios. Whether you're working with a simple script or a complex application, mastering *args and **kwargs will undoubtedly enhance your Python programming skills.

References

Were You Able to Follow the Instructions?

😍Love it!
😊Yes
😐Meh-gical
😞No
🤮Clickbait