Blog Post #102: Accepting Key-Value Arguments with **kwargs

In Post #101, we learned how to use *args to create flexible functions that can accept any number of positional arguments, which Python then collects into a tuple. But what about keyword arguments? Is there a way to write a function that can handle any number of named arguments that we don’t know about in advance?

The answer is yes, and the syntax is a natural extension of what we’ve already learned. In this post, we’ll learn how to use the double-asterisk ** syntax, commonly known as **kwargs, to create functions that can accept any number of keyword arguments.

The **kwargs Syntax

The **kwargs syntax in a function definition allows you to pass a variable number of keyword arguments to that function. Python will collect these arguments and pack them into a dictionary for you to use inside the function.

Let’s break down the name:

  • The important part is the double asterisk (**). This tells Python to collect all unassigned keyword arguments.
  • The name kwargs is a strong convention, short for “keyword arguments.” As with *args, you could technically name it something else (like **options), but it is highly recommended to stick with the **kwargs convention.

The basic syntax in a function definition looks like this:

def my_function(**kwargs):

A **kwargs Example: A Flexible Profile Builder

Let’s build a function that can create a user profile. Some users might provide their age, others their city, and some might provide both or neither. **kwargs is the perfect tool for this.

def build_profile(**user_info):
    """Creates a dictionary containing user information."""
    print(f"I received this info as a dictionary: {user_info}")
    print(f"The type is: {type(user_info)}")
    
    print("\nUser Profile:")
    # Inside the function, 'user_info' is a regular dictionary
    # so we can use .items() as we learned in Post #67
    if user_info:
        for key, value in user_info.items():
            print(f"- {key.title()}: {value}")
    else:
        print("- (No information provided)")

# Let's call it with different keyword arguments
build_profile(name="Alice", age=30)
print("-" * 20)
build_profile(name="Bob", city="New York", has_pets=True)

(Note: We used **user_info here to show that the name can be more descriptive, but **kwargs is the most common name.)

The output demonstrates how the keyword arguments are collected into a dictionary:

I received this info as a dictionary: {'name': 'Alice', 'age': 30}
The type is: <class 'dict'>

User Profile:
- Name: Alice
- Age: 30
--------------------
I received this info as a dictionary: {'name': 'Bob', 'city': 'New York', 'has_pets': True}
The type is: <class 'dict'>

User Profile:
- Name: Bob
- City: New York
- Has_Pets: True

As you can see, **user_info collected all the keyword arguments we passed and turned them into a dictionary, which our function was then able to process.

*args vs. **kwargs: A Quick Summary

It’s helpful to remember the clear distinction between these two powerful tools.

  • *args
    • Collects extra positional arguments.
    • Packs them into a tuple.
  • **kwargs
    • Collects extra keyword arguments.
    • Packs them into a dictionary.

What’s Next?

**kwargs gives your functions another layer of flexibility, allowing them to handle arbitrary named data. The pattern of collecting optional information into a dictionary is extremely common in Python libraries and frameworks.

We’ve now seen how to use standard parameters, *args, and **kwargs. But can they be used together in the same function? Yes, but there is a very strict order that must be followed. In Post #103, we will cover the definitive order for all argument types in a Python function signature.

Author

Debjeet Bhowmik

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com

Leave a Comment