Kodeclik Blog
How to set local variables from Python from Keyword Arguments (kwargs)
In Python, we typically define functions with a set number of parameters that we expect to receive. But what if you need more flexibility—say, when you don’t know in advance how many arguments a function might require?
That’s where Python’s variable argument features, *args and **kwargs, come into play. They let you create functions that can handle an arbitrary number of positional and keyword arguments, which is particularly useful when building reusable and dynamic functionality. In this blogpost, we will focus on **kwargs, a special syntax that lets a function accept any number of keyword arguments! (**args is for positional arguments, which is not the scope of this blogpost.)
Wow - you say, how can this be? If you use **kwargs, you can pass any number of argument to a function but yet in the code, you simply use the same **kwargs syntax in the call. In this blogpost, we’ll explore various methods for forwarding keyword arguments as parameters to a different function.
Example 1: Creating User Records
Consider the following code:
def create_user(username, age, address):
"""
Create a user with specified fields
"""
user = {
'username': username,
'age': age,
'address': address,
}
return user
# Example usage
new_user = create_user(
username='john_doe',
age = 18,
address = '123 Main Street'
)
print(new_user)
This code defines a create_user function that takes three parameters: username, age, and address. It then constructs and returns a dictionary containing those values as key-value pairs under the username, age, and address keys. In the example usage, create_user is called with 'john_doe', 18, and '123 Main Street', and the resulting dictionary is printed, showing how the user data has been encapsulated.
The output will be:
{'username': 'john_doe', 'age': 18, 'address': '123 Main Street'}
The only problem with the above code is that it has hardwired its arguments, namely username, age, and address.
What if you would like to add some ‘optional’ arguments, such as email, bio, or phone number? What if different users need different arguments? You cannot possibly write functions for each combination of available arguments. This is where *kwargs comes in.
Consider the code:
def create_user(**kwargs):
"""
Create a user using keyword arguments.
"""
user = {}
# Dynamically set local 'user' dictionary keys from kwargs
for key, value in kwargs.items():
user[key] = value
return user
# Example usage
user1 = create_user(
username='john_doe',
age = 18,
address = '123 Main Street',
bio = 'Coolest person on Main Street'
)
print(user1)
# Example usage, 2nd user
user2 = create_user(
username='john_doe_2',
age = 24,
address = '345 Littleton Avenue',
email = 'john.doe@mainstreet.com'
)
print(user2)
Here, **kwargs allows the function to accept any number of keyword arguments, and we loop through them to build the user dictionary—i.e., we’re “setting” those properties dynamically. Note that for user1, we have a bio field wheres for user2, we have an email field and yet the create_user() function is the same!
The output will be:
{'username': 'john_doe', 'age': 18, 'address': '123 Main Street', 'bio': 'Coolest person on Main Street'}
{'username': 'john_doe_2', 'age': 24, 'address': '345 Littleton Avenue', 'email': 'john.doe@mainstreet.com'}
as expected.
Example 2: Handling Required plus Optional Arguments in a Function
You can adapt the program above to make the function accept both mandatory (required) and optional arguments. Consider:
def greet_user(name, **kwargs):
"""
Greet a user and optionally print out additional details.
"""
greeting = f"Hello, {name}!"
print(greeting)
# Check if any extra details were provided
for key, value in kwargs.items():
print(f"{key.capitalize()}: {value}")
# Calling the function with optional keyword arguments
greet_user(
"Alice",
age=25,
location="New York",
profession="Engineer"
)
Note that we have defined a function greet_user that always expects a name parameter but can also accept arbitrary keyword arguments via **kwargs. Inside the function, we handle the additional details by iterating over kwargs and printing them. This approach makes the function flexible: you can pass any number of key-value pairs without changing the function signature but at the same time have the name argument as a required one.
The output will be:
Hello, Alice!
Age: 25
Location: New York
Profession: Engineer
Example 3: Forwarding **kwargs to Another Function
Here’s an example that forwards the **kwargs to another function where it is unpacked:
def make_api_request(endpoint, **kwargs):
"""
Make an API request to a given endpoint, passing along any additional
arguments to the underlying request function.
"""
# Suppose we have a function called `send_request` that accepts keyword args
response = send_request(endpoint, **kwargs)
return response
def send_request(url, headers=None, timeout=30, **kwargs):
"""
A mock function simulating a network call.
Accepts additional optional keyword arguments.
"""
print(f"Sending request to: {url}")
print(f"Using headers: {headers}, timeout: {timeout}")
print(f"Extra arguments: {kwargs}")
return {"status": "success"}
# Example usage
response_data = make_api_request(
"https://api.example.com/data",
headers={"Authorization": "Bearer token"},
timeout=60,
retries=3,
cache=True
)
print(response_data)
In this example, make_api_request() accepts an endpoint and an unspecified number of keyword arguments. It then calls send_request and forwards those keyword arguments using the **kwargs syntax. In send_request, we define specific keyword parameters (headers, timeout), but also account for any other keyword arguments that might come through. This pattern of passing **kwargs along is common in helper functions, decorators, or wrapper utilities when you don’t want to repeatedly redefine all possible parameters.
The output will be:
Sending request to: https://api.example.com/data
Using headers: {'Authorization': 'Bearer token'}, timeout: 60
Extra arguments: {'retries': 3, 'cache': True}
{'status': 'success'}
Conclusion
Leveraging **kwargs in Python empowers you to write more adaptable and maintainable code. Whether you need to dynamically set local variables, gracefully handle unknown or optional parameters, or simply forward data between functions, **kwargs offers a concise and expressive solution.
By incorporating these techniques into your workflow, you can accommodate evolving requirements and comfortably manage an unpredictable number of keyword arguments without constant refactoring.
Above all, remember to keep your function signatures meaningful and documentation clear, ensuring that the flexibility **kwargs provides doesn’t come at the cost of readability!
Enjoy this blogpost? Want to learn Python with us? Sign up for 1:1 or small group classes.