*args and **kwargs: Accepting a Variable Number of Arguments
We've learned how to define functions with a fixed number of positional and keyword arguments. But what if you want to create a function that can accept any number of arguments? For example, a function that can sum two numbers, or five, or a hundred. This is where *args and **kwargs come in, providing the ultimate flexibility for your function definitions.
📚 Prerequisites
To fully grasp this concept, you should be comfortable with:
- Defining and calling Python functions.
- Python data types, especially tuples and dictionaries.
- The difference between positional and keyword arguments.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅
*args: How to capture a variable number of positional arguments into a tuple. - ✅
**kwargs: How to capture a variable number of keyword arguments into a dictionary. - ✅ The Order of Operations: The correct order for using standard arguments,
*args, and**kwargsin a single function definition. - ✅ Unpacking: How to use the
*and**operators to pass arguments from a list/tuple or dictionary to a function.
🧠 Section 1: Handling Variable Positional Arguments with *args
The syntax *args in a function definition allows you to pass a variable number of positional arguments to your function. The single asterisk (*) is the important part; args is just a conventional name. These arguments are collected into a tuple.
Let's create the flexible sum_all function we imagined earlier.
# args_example.py
def sum_all(*numbers):
"""
Calculates the sum of all positional arguments passed to it.
'numbers' will be a tuple.
"""
print(f"Arguments received as a tuple: {numbers}")
total = 0
for num in numbers:
total += num
return total
# Call the function with different numbers of arguments
print(f"Sum 1: {sum_all(1, 2)}")
print(f"Sum 2: {sum_all(10, 20, 30, 40, 50)}")
print(f"Sum 3: {sum_all()}")
# Output:
# Arguments received as a tuple: (1, 2)
# Sum 1: 3
# Arguments received as a tuple: (10, 20, 30, 40, 50)
# Sum 2: 150
# Arguments received as a tuple: ()
# Sum 3: 0
Code Breakdown:
def sum_all(*numbers):defines a function that can take any number of positional arguments.- Inside the function,
numbersis a tuple containing all the arguments that were passed (e.g.,(1, 2)). - We can then iterate over this tuple just like any other tuple to perform our calculation.
💻 Section 2: Handling Variable Keyword Arguments with **kwargs
Similarly, the **kwargs syntax allows your function to accept any number of keyword (or named) arguments. The double asterisk (**) is the key; kwargs (short for "keyword arguments") is the convention. These arguments are collected into a dictionary.
This is incredibly useful for functions that need to handle arbitrary attributes or configuration options.
# kwargs_example.py
def display_user_profile(**user_info):
"""
Displays user information passed as keyword arguments.
'user_info' will be a dictionary.
"""
print(f"Arguments received as a dictionary: {user_info}")
if 'name' not in user_info:
print("Error: 'name' is a required field.")
return
print("\n--- User Profile ---")
for key, value in user_info.items():
print(f"{key.title()}: {value}")
print("--------------------")
# Call the function with different keyword arguments
display_user_profile(name="Brenda", age=42, city="Metropolis")
display_user_profile(name="Carlos", occupation="Engineer")
display_user_profile(age=30) # Missing the 'name' field
# Output:
# Arguments received as a dictionary: {'name': 'Brenda', 'age': 42, 'city': 'Metropolis'}
#
# --- User Profile ---
# Name: Brenda
# Age: 42
# City: Metropolis
# --------------------
# Arguments received as a dictionary: {'name': 'Carlos', 'occupation': 'Engineer'}
#
# --- User Profile ---
# Name: Carlos
# Occupation: Engineer
# --------------------
# Arguments received as a dictionary: {'age': 30}
# Error: 'name' is a required field.
Code Breakdown:
def display_user_profile(**user_info):defines a function that can take any number of keyword arguments.- Inside the function,
user_infois a dictionary containing all the keyword arguments (e.g.,{'name': 'Brenda', 'age': 42}). - We can then access the data using standard dictionary methods like
.items()or by checking for keys.
🛠️ Section 3: Putting It All Together
You can combine regular arguments, *args, and **kwargs in a single function. When you do, they must appear in this specific order:
- Standard positional arguments
*args**kwargs
# all_together_example.py
def process_order(order_id, *items, **customer_details):
"""Processes a customer order with required and optional details."""
print(f"Processing Order ID: {order_id}")
print("\nItems in Order:")
for item in items:
print(f"- {item}")
print("\nCustomer Details:")
for key, value in customer_details.items():
print(f"- {key.title()}: {value}")
process_order(
101,
"Laptop", "Mouse", "Keyboard",
name="Diana Prince",
shipping_address="25 Paradise Island"
)
# Output:
# Processing Order ID: 101
#
# Items in Order:
# - Laptop
# - Mouse
# - Keyboard
#
# Customer Details:
# - Name: Diana Prince
# - Shipping_Address: 25 Paradise Island
🚀 Section 4: The Reverse: Unpacking with * and **
The * and ** operators can also be used when calling a function. This is called unpacking.
*unpacks a list or tuple into positional arguments.**unpacks a dictionary into keyword arguments.
# unpacking_example.py
def create_point(x, y, z):
"""Creates a 3D point."""
print(f"Point created at (x={x}, y={y}, z={z})")
# Unpacking a list/tuple with *
coords_list = [10, 20, 30]
create_point(*coords_list)
# Unpacking a dictionary with **
coords_dict = {'x': 5, 'y': 15, 'z': 25}
create_point(**coords_dict)
# Output:
# Point created at (x=10, y=20, z=30)
# Point created at (x=5, y=15, z=25)
This is extremely useful when you have data in a list or dictionary and need to pass it to a function that expects individual arguments.
✨ Conclusion & Key Takeaways
*args and **kwargs are powerful tools that allow you to write highly flexible functions that can handle a wide variety of inputs. While you may not use them in every function you write, they are essential for building adaptable frameworks, decorators, and utilities.
Let's summarize the key takeaways:
*argsfor Positional: Captures an unlimited number of positional arguments into a tuple.**kwargsfor Keyword: Captures an unlimited number of keyword arguments into a dictionary.- Order is Key: In a function definition, the order must be:
standard_args,*args,**kwargs. - Unpacking is the Opposite: Use
*and**during a function call to pass arguments from lists and dictionaries.
Challenge Yourself:
Write a function called generate_html_tag that takes a tag_name as a required positional argument (e.g., "p", "h1", "div"). It should also accept any number of keyword arguments, which will be the HTML attributes (e.g., class_="intro", id="main"). The function should return a string representing the HTML tag. For example, generate_html_tag("p", class_="text-bold") should return <p class_="text-bold"></p>.
➡️ Next Steps
You've now unlocked a new level of function flexibility. Next, we will explore a concept that is crucial for understanding how variables are accessed within different parts of your program: "Scope: Local, Enclosing, Global, and Built-in (LEGB rule)."
Happy coding!
Glossary (Python Terms)
*args: A special syntax in a function definition to capture a variable number of positional arguments into a tuple.**kwargs: A special syntax to capture a variable number of keyword arguments into a dictionary.- Unpacking: The process of using
*or**to pass items from an iterable (like a list or dictionary) as individual arguments into a function call.