How to pass keyword arguments in Python
Learn how to pass keyword arguments in Python. Explore different methods, tips, real-world applications, and common error debugging.
.png)
Keyword arguments in Python make function calls more explicit and readable. They allow you to pass arguments in any order, which adds flexibility and clarity to your code.
In this article, you’ll find techniques, real-world applications, and debugging advice. These tips will help you master keyword arguments and write more robust Python functions.
Basic keyword arguments
def greet(name, message):
return f"{message}, {name}!"
result = greet(name="Alice", message="Hello")
print(result)--OUTPUT--Hello, Alice!
In the example, the greet function is called using name="Alice" and message="Hello". This explicitly assigns each value to its corresponding parameter, which makes the code more self-documenting. You don't have to check the function definition to understand what each argument does.
This technique offers two key benefits:
- Clarity: The purpose of each argument is immediately clear from the function call itself.
- Flexibility: You could call the function as
greet(message="Hello", name="Alice")and get the exact same output. The order doesn't matter when you use keyword arguments.
Basic keyword argument techniques
Building on this foundation, you can enhance your functions by using the ** operator, setting default values, and combining positional with keyword arguments.
Using ** to pass keyword arguments
def display_info(name, age, location):
return f"{name} is {age} years old and lives in {location}."
user_data = {"name": "Bob", "age": 30, "location": "New York"}
print(display_info(**user_data))--OUTPUT--Bob is 30 years old and lives in New York.
The double-asterisk operator ** unpacks a dictionary, turning its key-value pairs into keyword arguments for a function. In the example, **user_data effectively calls the display_info function as if you had written display_info(name="Bob", age=30, location="New York").
- Dynamic Data: It's perfect for when your arguments come from a dynamic source, like an API response or user input stored in a dictionary.
- Code Readability: This technique keeps your function calls clean, especially when you're working with functions that have many parameters.
Default values for keyword arguments
def create_profile(name, occupation, location="Unknown", age=None):
profile = {"name": name, "occupation": occupation, "location": location}
if age:
profile["age"] = age
return profile
print(create_profile(name="Charlie", occupation="Developer"))--OUTPUT--{'name': 'Charlie', 'occupation': 'Developer', 'location': 'Unknown'}
You can make function arguments optional by assigning them default values. In the create_profile function, location and age are optional. If you don't provide them when you call the function, Python uses the predefined defaults.
- Flexibility: The function call only needs to include the required arguments, like
nameandoccupation. - Predictable State: Setting
location="Unknown"ensures the profile always has a location value. Usingage=Noneis a standard way to handle optional data that might be absent.
Mixing positional and keyword arguments
def calculate_total(base_price, tax_rate, discount=0):
return base_price * (1 + tax_rate) * (1 - discount)
# Using both positional and keyword arguments
print(calculate_total(100, 0.1, discount=0.05))
print(calculate_total(100, tax_rate=0.1, discount=0.05))--OUTPUT--104.5
104.5
You can mix positional and keyword arguments in a single function call, but there's one firm rule: positional arguments must always come first. In the calculate_total function, 100 is passed positionally for base_price. After that, you can use keyword arguments for any of the remaining parameters.
- This structure prevents ambiguity and helps Python correctly assign values.
- Once you use a keyword argument, all subsequent arguments must also be keyword arguments. For example,
calculate_total(100, discount=0.05, 0.1)would raise an error.
Advanced keyword argument techniques
Building on those techniques, you can write even more flexible functions using features like **kwargs for variable arguments and * to enforce keyword-only inputs.
Using **kwargs for variable keyword arguments
def create_user(**kwargs):
user = {"created_at": "2023-01-01"}
user.update(kwargs)
return user
user = create_user(username="python_dev", email="[email protected]", level="advanced")
print(user)--OUTPUT--{'created_at': '2023-01-01', 'username': 'python_dev', 'email': '[email protected]', 'level': 'advanced'}
The **kwargs parameter lets your function accept any number of keyword arguments. It gathers them into a dictionary, which is conventionally named kwargs. In the create_user function, this allows you to pass any user attributes you want, such as username or email, without defining them in advance.
- Ultimate Flexibility: You aren't limited to a predefined set of parameters. This is ideal for handling data with varying fields, like API responses or configuration settings.
- Clean Implementation: The function uses
user.update(kwargs)to merge all the provided keyword arguments into a base dictionary, creating a complete user object in a single, efficient line.
Forcing keyword-only arguments with *
def configure_app(*, debug=False, cache_size=1024, timeout=30):
config = f"Debug: {debug}, Cache: {cache_size}MB, Timeout: {timeout}s"
return config
# Must use keyword arguments for all parameters
print(configure_app(debug=True, timeout=60))--OUTPUT--Debug: True, Cache: 1024MB, Timeout: 60s
The bare asterisk * in the function signature forces all subsequent parameters to be keyword-only, meaning you can't pass them based on their position. For the configure_app function, you must explicitly name each argument you pass, such as debug=True.
- Error Prevention: This prevents bugs from passing arguments in the wrong order, a common issue with functions that have many optional parameters with default values.
- Improved Readability: Your function calls become self-documenting. It’s immediately clear what each value represents without needing to look up the function’s definition.
Type hints with keyword arguments
from typing import Dict, Any, Optional
def process_data(data: Dict[str, Any], *, retry: bool = False,
timeout: Optional[int] = None) -> Dict[str, Any]:
result = data.copy()
result["processed"] = True
result["retry_enabled"] = retry
result["timeout"] = timeout
return result
print(process_data({"id": 123}, retry=True, timeout=30))--OUTPUT--{'id': 123, 'processed': True, 'retry_enabled': True, 'timeout': 30}
Adding type hints to your keyword arguments makes your function's contract crystal clear. In the process_data function, the signature communicates everything you need to know about how to use it correctly.
- The
dataparameter is typed asDict[str, Any], specifying it should be a dictionary with string keys. - Keyword-only arguments like
retry: boolandtimeout: Optional[int]define their expected types and default values. - The
-> Dict[str, Any]at the end declares what type of value the function will return.
This combination helps static analysis tools catch bugs before you even run the code, making your functions more robust and easier to use.
Move faster with Replit
Replit is an AI-powered development platform that comes with all Python dependencies pre-installed, so you can skip setup and start coding instantly. Instead of piecing together techniques, you can describe the app you want to build and Agent 4 will take it from idea to working product. For example, you could create:
- An interactive pricing calculator that uses keyword arguments for optional fees and discounts, similar to the
calculate_totalfunction. - A configuration generator for a web server that uses
**kwargsto accept a flexible set of settings likeport,hostname, andlog_level. - A data enrichment tool that processes user records, adding metadata like
statusorlast_updatedby passing optional flags to a processing function.
Simply describe your app, and Replit will write the code, test it, and fix issues automatically, all within your browser.
Common errors and challenges
Even with their benefits, keyword arguments can lead to tricky errors if you're not aware of a few common pitfalls.
Avoiding the SyntaxError with positional arguments after keyword arguments
One of the first hurdles you might hit is a SyntaxError for placing positional arguments after keyword arguments. Python enforces a strict order: positional arguments always come first. Once you've used a keyword argument like name="Alice", all following arguments must also be keyword arguments.
This rule exists to prevent ambiguity. If you were to call a function like my_func(arg1="value", "another_value"), Python wouldn't know which parameter "another_value" is supposed to fill. Sticking to the "positional-first" rule keeps your function calls predictable and error-free.
Dealing with the mutable default argument trap
A more subtle issue is the "mutable default argument trap." This happens when you use a mutable object, like a list or dictionary, as a default value. For example, in a function defined as def add_to_list(item, target_list=[]), the empty list [] is created only once—when the function is first defined, not each time it's called.
- If you call
add_to_list("apple"), it works as expected. - But if you then call
add_to_list("banana"), you'll get["apple", "banana"]because you're modifying the same list from the first call.
The standard solution is to use an immutable default like None and create a new list inside the function. You'd rewrite the function as def add_to_list(item, target_list=None): and then start with if target_list is None: target_list = []. This ensures every call gets a fresh list if one isn't provided.
Preventing duplicate keyword arguments with **kwargs
When you're using **kwargs to pass a dictionary of arguments, you can accidentally provide a value for the same parameter twice. This results in a TypeError because a function can't accept multiple values for the same argument. For instance, calling a function process_data(user_id=123, **{'user_id': 456}) will fail.
This error often occurs when a function has both explicit keyword arguments and a **kwargs parameter. To avoid it, you need to ensure the dictionary you're unpacking doesn't contain keys that match the function's other named parameters. A good practice is to filter your dictionary beforehand or design your functions to clearly separate explicit parameters from the flexible ones collected by **kwargs.
Avoiding the SyntaxError with positional arguments after keyword arguments
Python requires positional arguments to appear before any keyword arguments in a function call. This strict ordering prevents ambiguity. If you mix them up, you'll get a SyntaxError. The following code demonstrates this common mistake with the create_report function.
def create_report(title, description, author="Unknown", date=None):
return f"Report: {title} by {author}, {description}, Date: {date}"
# Error: positional argument follows keyword argument
result = create_report(title="Sales Data", "Q4 performance summary", date="2023-12-31")
print(result)
The function call is invalid because the positional argument "Q4 performance summary" follows the keyword argument title="Sales Data". Once a keyword argument is used, all subsequent arguments must also be keywords. The corrected code below shows the proper structure.
def create_report(title, description, author="Unknown", date=None):
return f"Report: {title} by {author}, {description}, Date: {date}"
# Correct: positional arguments before keyword arguments
result = create_report("Sales Data", "Q4 performance summary", date="2023-12-31")
print(result)
The corrected call works because it respects Python's ordering rule: positional arguments first, then keywords. By passing "Sales Data" and "Q4 performance summary" before date="2023-12-31", the call becomes unambiguous. This error often appears when functions have several optional parameters, so it's a good habit to be mindful of the argument order to prevent unexpected syntax errors and keep your function calls clean and predictable.
Dealing with the mutable default argument trap
A classic Python pitfall is using a mutable object, like a list, as a default argument. This can cause unexpected side effects because the same list is reused across multiple function calls, leading to data from one call bleeding into the next.
The add_user function below seems straightforward, but it hides this very trap. Notice what happens when you call it twice—the second call doesn't start with a fresh list, which is often not what you want.
def add_user(name, user_list=[]):
user_list.append(name)
return user_list
print(add_user("Alice")) # ['Alice']
print(add_user("Bob")) # ['Alice', 'Bob'] - Unexpected!
The default user_list is created only once, so each call to add_user modifies the same object in memory. This is why the list grows unexpectedly. The corrected implementation below demonstrates the standard fix for this behavior.
def add_user(name, user_list=None):
if user_list is None:
user_list = []
user_list.append(name)
return user_list
print(add_user("Alice")) # ['Alice']
print(add_user("Bob")) # ['Bob']
The fix is to set the default value to None instead of an empty list. Inside the add_user function, a check—if user_list is None:—creates a new list only when one isn't provided. This simple pattern ensures each function call works with a fresh, independent list, preventing data from one call from unintentionally affecting another.
Keep an eye out for this behavior whenever you use a mutable type, like a list or dictionary, as a default argument.
Preventing duplicate keyword arguments with **kwargs
When you mix explicit keyword arguments with **kwargs, you can accidentally provide the same argument twice, triggering a TypeError. This common mistake occurs when a key in your unpacked dictionary clashes with a named parameter. See how it unfolds below.
def process_order(item_id, quantity, **options):
return f"Processing {quantity} of item {item_id} with {options}"
data = {"quantity": 5, "express": True}
# Error: duplicate keyword argument 'quantity'
result = process_order(item_id=1234, quantity=2, **data)
print(result)
Here, the process_order function receives quantity twice: once as a direct argument and again from the **data dictionary. This ambiguity causes the error. See how to fix this in the code below.
def process_order(item_id, quantity, **options):
return f"Processing {quantity} of item {item_id} with {options}"
data = {"express": True}
# Correct: no duplicate parameters
result = process_order(item_id=1234, quantity=2, **data)
print(result)
The fix works because the data dictionary no longer contains a quantity key, resolving the conflict. Now, quantity is passed only once as an explicit argument, while **options safely collects the remaining key-value pairs from data.
This error often arises when a function’s named parameters might overlap with keys from a dictionary you’re unpacking. It’s a good practice to filter your dictionary beforehand to avoid such clashes, especially with dynamic data sources.
Real-world applications
Moving beyond potential errors, keyword arguments shine in practical applications like configuring database connections and building flexible data analysis functions.
Creating a database connection with keyword arguments
Keyword arguments are especially useful for functions with numerous configuration options, like establishing a database connection, as they allow you to specify only the parameters that differ from the defaults.
def connect_to_database(host="localhost", port=5432, username="admin",
password=None, database="main", ssl=False):
conn_string = f"postgresql://{username}:{password}@{host}:{port}/{database}"
if ssl:
conn_string += "?sslmode=require"
return f"Connected to: {conn_string}"
print(connect_to_database(host="db.example.com", database="users", ssl=True))
The connect_to_database function uses keyword arguments to make configuration settings clear and manageable. Each parameter is given a sensible default, such as host="localhost", which simplifies common use cases. The function call itself becomes self-documenting; it’s immediately obvious what values are being assigned to host, database, and ssl.
- This method improves code readability, as you don't need to remember the parameter order.
- The function also demonstrates how to handle optional flags, like using an
if ssl:check to modify the final connection string.
Building a flexible data analysis function with **kwargs
The **kwargs parameter is a powerful tool for creating flexible data analysis functions that can accept any number of custom settings.
def analyze_data(data, *, method="mean", normalize=False, **kwargs):
result = f"Analyzing {len(data)} data points using {method}"
if normalize:
result += " with normalization"
if kwargs:
options = ", ".join(f"{k}={v}" for k, v in kwargs.items())
result += f" and options: {options}"
return result
data = [10, 25, 30, 45, 50]
print(analyze_data(data, method="regression", normalize=True,
confidence=0.95, iterations=1000))
The analyze_data function showcases a robust design pattern by combining keyword-only arguments with a flexible catch-all. This approach creates a function that is both explicit about its core options and adaptable enough for advanced use cases.
- The bare asterisk (
*) forces arguments likemethodandnormalizeto be passed by name, which improves clarity and prevents positional mistakes. - Meanwhile,
**kwargscollects any additional keyword arguments, such asconfidence=0.95anditerations=1000, into a dictionary for custom processing.
Get started with Replit
Put these techniques into practice by building a tool. Describe what you want to Replit Agent, like “a price calculator with optional keyword arguments for discounts and taxes” or “a data analysis function that accepts custom filters.”
Replit Agent writes the code, tests for errors, and can even deploy your app. Start building with Replit.
Describe what you want to build, and Replit Agent writes the code, handles the infrastructure, and ships it live. Go from idea to real product, all in your browser.
Create & deploy websites, automations, internal tools, data pipelines and more in any programming language without setup, downloads or extra tools. All in a single cloud workspace with AI built in.

.png)
.png)
.png)