Search⌘ K
AI Features

Default and Keyword Arguments

Explore how default and keyword arguments enhance function flexibility in Python. Learn to set optional parameters with defaults, call functions using named arguments to improve readability, and understand rules for mixing argument types. Understand potential pitfalls with mutable defaults and how to avoid common bugs by using None as a safe default. This lesson helps you write more adaptable and clear Python functions.

In earlier lessons, we worked with functions that required a fixed number of arguments, provided in a specific order. While this is useful for learning the basics, real-world programs rarely operate under such strict conditions. Data is often incomplete, optional, or variable.

Consider a function that creates a user profile. A username may be required, but details like an address or profile picture maybe optional. Forcing callers to supply every possible value makes functions harder to use and easier to misuse.

By learning default arguments and keyword arguments, we can write flexible functions. These features allow functions to adapt to different inputs while maintaining clear and predictable behavior.

Default arguments: Making parameters optional

When defining a function, we often want some parameters to have reasonable default values that are used unless the caller explicitly provides a different one. These are known as default arguments. We create them by assigning a value to a parameter directly in the function definition using the assignment operator (=).

When the function is called:

  • If the caller provides a value for that parameter, the function uses the provided argument.

  • If the caller omits the argument, the function automatically falls back to the default value.

When defining functions, Python enforces a strict rule, "required parameters (non-defaults) must be defined before optional parameters (defaults)." If we place an optional parameter before a required one, the Python interpreter can not reliably map positional arguments to the required parameters.

Python 3.14.0
def create_profile(username, role="Subscriber"):
# The 'role' parameter defaults to "Subscriber" if not provided
print(f"User: {username}")
print(f"Role: {role}")
print("---")
# 1. Calling with only the required argument
create_profile("jdoe_99")
# 2. Calling with both arguments to override the default
create_profile("admin_user", "Administrator")
  • Line 1: We define create_profile with two parameters. role is assigned a default value of "Subscriber".

  • Lines 3–5: The function prints the provided username and role.

  • Line 8: We call the function passing only "jdoe_99". Python assigns this to username and uses the default value, "Subscriber", for role.

  • Line 11: Next, we call the function with two arguments. This time "Administrator" overrides the default value.

Keyword arguments: Calling functions flexibly

So far, we have passed arguments by position: the first value goes to the first parameter, the second to the second, and so on. However, as functions grow complex, remembering the exact order of five or six parameters becomes difficult and error-prone.

Python allows us to use keyword arguments in our function calls. We explicitly name the parameter we are setting (e.g., name="value"). This improves readability because the code clearly states what each value represents. It also frees us from strict ordering; if we use keywords, we can pass arguments in any order we like.

Python 3.14.0
def describe_pet(pet_name, animal_type, age):
print(f"I have a {animal_type} named {pet_name}.")
print(f"It is {age} years old.")
# 1. Positional call (Order matters strictly)
describe_pet("Luna", "cat", 4)
# 2. Keyword call (Order does not matter)
describe_pet(age=4, pet_name="Luna", animal_type="cat")
  • Lines 1–3: We define a function requiring three parameters: pet_name, animal_type, and age.

  • Line 6: We call the function positionally. We must remember that "Luna" comes before "cat", and "cat" comes before 4.

  • Line 9: Here, we call the function using keywords. Even though age is the last parameter in the definition, we can pass it first here. Python automatically matches values to the correct variable names.

The rules of mixing argument types

We can mix positional and keyword arguments in a single call, but Python enforces a strict rule that the positional arguments must always come before keyword arguments. This rule exists to prevent ambiguity. If we provided a keyword argument first, and then a positional one, Python wouldn't know which remaining parameter the positional value belongs to.

Try running the code below. It contains a deliberate error.

Python 3.14.0
def calculate_total(price, tax, discount):
final_price = price + (price * tax) - discount
print(f"Total: ${final_price}")
# ERROR: A positional argument (5) follows a keyword argument (tax=0.08)
calculate_total(price=100, tax=0.08, 5)
  • Line 6: This line fails because the positional argument 5 comes after the keyword argument tax=0.08.

How to resolve? To fix the error in the code above, replace line 6 with this valid call where the positional argument comes first: calculate_total(100, tax=0.08, discount=5)

The mutable default trap

There is one important detail regarding default arguments that catches almost every Python beginner. It stems from how Python handles function definitions in memory.

Problem: Python evaluates default argument values only once, when the function is defined, not every time the function is called.

If you use a mutable object (like a list [] or dictionary {}) as a default value, Python creates that object exactly once. Every single time you call the function without providing that argument, Python recycles the same list.

  • If Call A adds an item to the list, that item stays there.

  • When Call B runs, it sees the item added from Call A.

This creates "phantom" data that leaks from one function call to the next, causing bugs that are very hard to track down.

To avoid this, we never use mutable objects as defaults. Instead, we use None as the default value. Inside the function, we check for None and create a fresh list. This ensures every call gets its own brand-new empty list.

Python
# The "Safe" Pattern for mutable defaults
def add_student(student_name, class_list=None):
# If the caller didn't provide a list, create a NEW one now
if class_list is None:
class_list = []
class_list.append(student_name)
print(f"Class list: {class_list}")
add_student("Alice")
add_student("Bob")
  • Line 2: We set class_list to default to None (which is immutable) instead of [].

  • Lines 4–5: We check if class_list is None. If it is, we create a fresh, empty list. This happens during the call, guaranteeing a new list every time.

  • Line 10: Calling the function creates a new list containing only "Alice".

  • Line 11: Calling it again creates a fresh list containing only "Bob". If we had used class_list=[], "Bob" would have been added to Alice's list!

By using default and keyword arguments, we shift the burden of complexity from the caller to the function author. We can create functions that have sensible defaults for standard behavior but remain completely customizable for advanced scenarios. We also make our code significantly more readable by allowing explicit parameter naming. However, we must respect the ordering rules: positional before keyword in calls, and required before default in definitions to keep our syntax valid.