intermediate

Keyword Arguments (**kwargs)

Learn to accept any number of keyword arguments with **kwargs.

**kwargs allows functions to accept any number of keyword arguments, providing ultimate flexibility for function calls with named parameters stored as a dictionary.

πŸ“š Concepts & Theory

kwargs allows functions to accept any number of keyword (named) arguments. The double asterisk () unpacks keyword arguments into a dictionary.

Basic kwargs Syntax:

def function_name(kwargs):
# kwargs is a dictionary
for key, value in kwargs.items():
print(f"{key}: {value}")

Simple Example:

def print_info(kwargs):
for key, value in kwargs.items():
print(f"{key} = {value}")

print_info(name="Alice", age=30, city="NYC")
# name = Alice
# age = 30
# city = NYC

Building User Profiles:

def create_profile(details):
profile = {
"username": details.get("username", "anonymous"),
"email": details.get("email"),
"age": details.get("age"),
}
return profile

user = create_profile(username="alice", email="[email protected]", age=25)

Accessing kwargs:

def process(kwargs):
# Get with default
name = kwargs.get("name", "Unknown")

# Check if key exists
if "age" in kwargs:
print(f"Age: {kwargs['age']}")

# Iterate all
for key, value in kwargs.items():
print(f"{key}: {value}")

Mixing Parameters with kwargs:

def greet(greeting, kwargs):
name = kwargs.get("name", "there")
age = kwargs.get("age")

msg = f"{greeting}, {name}!"
if age:
msg += f" You are {age} years old."
return msg

greet("Hello", name="Alice", age=30)

Complete Parameter Order:**

def full_function(required, *args, keyword_only, **kwargs):
pass

# Call examples:
full_function(
1, # required
2, 3, # *args
keyword_only=4, # keyword_only
extra1=5, # kwargs
extra2=6 #
kwargs
)

Common Use Cases:

1. Configuration Functions:

def configure_server(config):
host = config.get("host", "localhost")
port = config.get("port", 8080)
debug = config.get("debug", False)
return f"Server: {host}:{port} (debug={debug})"

configure_server(host="0.0.0.0", port=5000, debug=True)

2. Building Dictionaries:

def build_user(data):
return {
"id": data.get("id"),
"name": data.get("name", "Anonymous"),
"created": datetime.now(),
data # Include all other kwargs
}

3. Flexible Object Creation:

def create_car(specs):
car = {
"brand": specs.get("brand", "Unknown"),
"model": specs.get("model", "Unknown"),
"year": specs.get("year", 2024)
}
car.update(specs) # Add any additional specs
return car

Unpacking Dictionaries:

def greet(name, age):
return f"{name} is {age}"

user_data = {"name": "Alice", "age": 30}
result = greet(user_data) # Unpacks dict into kwargs
# Same as: greet(name="Alice", age=30)

Combining *args and kwargs:

def super_flexible(*args, kwargs):
print("Positional:", args)
print("Keyword:", kwargs)

super_flexible(1, 2, 3, name="Alice", age=30)
# Positional: (1, 2, 3)
# Keyword: {'name': 'Alice', 'age': 30}

Forwarding Arguments:

def wrapper(kwargs):
# Pass all kwargs to another function
return actual_function(kwargs)

Type Hints (Python 3.8+):

from typing import Any

def process(kwargs: Any) -> dict:
return kwargs

Best Practices:

  • Use descriptive parameter name: options, settings, **metadata

  • Document expected keywords

  • Provide sensible defaults with .get()

  • Validate required keywords

  • Consider if explicit parameters would be clearer

🎯 Your Challenge

Create a function build_user(**user_data) that creates and returns a dictionary with all provided keyword arguments.

πŸ“ Starter Code

Python
def build_user(**user_data):
    pass
  • Use **user_data to accept any keyword arguments
  • **kwargs automatically creates a dictionary
  • Simply return the user_data dictionary
  • No need for loops or processing in this simple case
  • The function should accept and return all provided keyword arguments

Solution

Python
def build_user(**user_data):
    return user_data

Explanation

This function demonstrates **kwargs at its simplest. The ** before user_data tells Python to collect all keyword arguments into a dictionary. When you call build_user(name="Alice", age=30, email="[email protected]"), Python creates user_data = {"name": "Alice", "age": 30, "email": "[email protected]"}. Since we want to return exactly that dictionary, we simply return user_data. The function is flexibleβ€”it accepts any keyword arguments without defining them explicitly. You could call it with any combination of keys: build_user(username="bob") or build_user(first="John", last="Doe", city="NYC") all work.

⚠️ Common Mistakes to Avoid

  • Forgetting the ** in the parameter definition
  • Trying to access kwargs with dot notation (it's a dict, not object)
  • Not using .get() for optional keys (causes KeyError)
  • Expecting kwargs to be ordered in old Python versions
  • Modifying the original kwargs dict and causing side effects

❓ Frequently Asked Questions

*args captures positional arguments as a tuple. **kwargs captures keyword arguments as a dictionary.
Yes! Order matters: def func(required, *args, **kwargs). *args must come before **kwargs.
Use dictionary methods: kwargs.get('key'), kwargs['key'], or iterate with kwargs.items().
Yes, in Python 3.7+ dictionaries maintain insertion order, so kwargs preserves the order of arguments.

πŸ”— Related Exercises