Skip to main content

Default Arguments and Keyword Arguments

We've learned how to define functions, pass information to them, and get values back using the **[return statement]**. Now, let's make our functions more flexible and readable. This article explores two powerful features: default arguments and keyword arguments, which allow you to make function parameters optional and your function calls more explicit.


📚 Prerequisites

Before you start, make sure you understand:

  • How to define and call a Python function.
  • The difference between parameters and arguments.
  • Positional arguments (passing arguments based on their order).

🎯 Article Outline: What You'll Master

In this article, you will learn:

  • Default Arguments: How to assign a default value to a parameter, making it optional during a function call.
  • A Critical Pitfall: The "mutable default argument" trap and how to avoid it.
  • Keyword Arguments: How to improve the clarity and flexibility of your function calls by naming arguments.
  • Combining Argument Types: The rules for mixing positional, keyword, and default arguments in a single function call.

🧠 Section 1: Making Parameters Optional with Default Arguments

Imagine you have a function that sends a greeting. Most of the time, you want a simple greeting, but sometimes you want a more formal one.

Without default arguments, you might have to create two different functions:

def simple_greet(name):
print(f"Hello, {name}!")

def formal_greet(name, title):
print(f"Hello, {title} {name}!")

This is repetitive. A better way is to use a default argument. You can assign a default value to a parameter directly in the function definition using the = operator.

# function_with_default_argument.py

def greet(name, title=""):
"""Greets a person, with an optional title."""
if title:
print(f"Hello, {title} {name}!")
else:
print(f"Hello, {name}!")

# Calling the function in different ways
greet("Alice") # The 'title' parameter uses its default value ""
greet("Dr. Smith", "Dr.") # We provide a value for 'title'
greet("Professor Plum", title="Professor") # Using a keyword argument

# Output:
# Hello, Alice!
# Hello, Dr. Smith!
# Hello, Professor Plum!

How it Works:

  • If an argument for the parameter is provided in the function call, Python uses that argument.
  • If no argument is provided, Python uses the default value specified in the definition.

The Golden Rule of Order: When defining a function, all parameters with default values must come after all parameters without default values.

# This is CORRECT
def create_user(username, is_active=True):
# ...
pass

# This will cause a SyntaxError
# def create_user(is_active=True, username):
# # ...
# pass

💻 Section 2: The Mutable Default Argument Pitfall

This is one of the most common "gotchas" for new Python programmers. Default argument values are created only once, when the function is defined, not each time it's called.

This is fine for immutable types like numbers, strings, or tuples. But it can lead to unexpected behavior with mutable types like lists or dictionaries.

Let's see the problem:

# mutable_default_problem.py

def add_item_to_list(item, target_list=[]):
"""This function has a dangerous default argument."""
target_list.append(item)
print(f"Items in list: {target_list}")

add_item_to_list("apple")
add_item_to_list("banana")
add_item_to_list("cherry")

# Expected Output (for each call):
# Items in list: ['apple']
# Items in list: ['banana']
# Items in list: ['cherry']

# Actual Output:
# Items in list: ['apple']
# Items in list: ['apple', 'banana']
# Items in list: ['apple', 'banana', 'cherry']

Because the [] list is created only once, every call to add_item_to_list modifies the exact same list.

The Solution: Use None as the Default The standard Pythonic way to handle this is to use None as the default value and then create a new mutable object inside the function if one isn't provided.

# mutable_default_solution.py

def add_item_to_list_safe(item, target_list=None):
"""A safe way to handle mutable default arguments."""
if target_list is None:
target_list = [] # Create a new list only when needed
target_list.append(item)
print(f"Items in list: {target_list}")

add_item_to_list_safe("apple")
add_item_to_list_safe("banana")
add_item_to_list_safe("cherry")

# Correct Output:
# Items in list: ['apple']
# Items in list: ['banana']
# Items in list: ['cherry']

🛠️ Section 3: Improving Readability with Keyword Arguments

We've already seen keyword arguments, but let's formalize them. A keyword argument is where you explicitly name the parameter you are providing a value for.

# keyword_arguments_example.py

def create_database_connection(host, port, username, password, timeout=30):
"""Establishes a database connection."""
print(f"Connecting to {host}:{port} as {username}...")
print(f"Timeout is set to {timeout} seconds.")

# Calling with positional arguments can be confusing. What does 3306 mean?
create_database_connection("localhost", 3306, "admin", "s3cr3t")

# Calling with keyword arguments is self-documenting and clear.
create_database_connection(
host="localhost",
port=3306,
username="admin",
password="s3cr3t"
)

# The order doesn't matter with keyword arguments.
create_database_connection(
password="s3cr3t",
username="admin",
port=3306,
host="localhost"
)

Key Benefits:

  • Readability: It's immediately obvious what each value represents.
  • Flexibility: You don't have to remember the exact order of the parameters. This is invaluable for functions with many parameters.

The Second Golden Rule of Order: You can mix positional and keyword arguments, but all positional arguments must come before any keyword arguments.

# This is CORRECT
create_database_connection("localhost", 3306, password="s3cr3t", username="admin")

# This will cause a SyntaxError
# create_database_connection(host="localhost", 3306, username="admin", password="s3cr3t")

✨ Conclusion & Key Takeaways

Default and keyword arguments are powerful tools for writing functions that are more readable, flexible, and robust. Using them effectively will make your code easier for you and others to understand and maintain.

Let's summarize the key takeaways:

  • Default Arguments Make Parameters Optional: Use parameter=value in the function definition to provide a fallback value.
  • Beware Mutable Defaults: Never use a mutable object like a list or dictionary as a default argument. Use None and create it inside the function instead.
  • Keyword Arguments Improve Clarity: Use parameter=value in the function call to make your code self-documenting.
  • Order Matters: In function definitions, defaults go last. In function calls, positionals come first.

Challenge Yourself: Modify the describe_pet function from the last article. Give the animal_type parameter a default value of "dog". Call the function in three ways:

  1. To describe a "cat" named "Whiskers".
  2. To describe a dog named "Buddy" without specifying the animal type.
  3. To describe a "hamster" named "Fuzzy" using keyword arguments for both parameters.

➡️ Next Steps

You've now mastered the most common ways to pass arguments to functions. But what happens when you don't know how many arguments you'll receive? In the next article, we'll explore a powerful feature for handling a variable number of arguments: "*args and **kwargs."

Keep practicing, and enjoy the newfound clarity in your function calls!


Glossary (Python Terms)

  • Default Argument: A parameter in a function definition that has a pre-assigned value.
  • Keyword Argument: An argument passed to a function where you explicitly specify the parameter name.
  • Immutable: An object whose state cannot be modified after it is created (e.g., numbers, strings, tuples).
  • Mutable: An object whose state can be modified after it is created (e.g., lists, dictionaries, sets).

Further Reading (Python Resources)