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

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