Python Function Default Arguments: Basics and Why You Should Avoid Mutable Defaults

When defining a function, setting a value for an argument beforehand allows you to omit that argument when calling the function. This is called a “Default Argument.” While this is a very convenient feature, you need to be careful with Python’s specific behavior when setting “mutable objects” like lists or dictionaries as default values.

This article explains the basic usage of default arguments and how to avoid a common “pitfall.”


目次

Basic Usage of Default Arguments

You can set a default value by using the format argument_name=value when defining the function. As an example, let’s create a function that receives a product price and a consumption tax rate to calculate the price including tax. Since the tax rate doesn’t change frequently, we set 0.1 (10%) as the default.

def calculate_price_with_tax(price, tax_rate=0.1):
    """
    Calculate price with tax.
    If tax_rate is omitted, 0.1 is applied.
    """
    return int(price * (1 + tax_rate))

# 1. When the argument is omitted (Default value 0.1 is used)
print(f"1000 yen with tax: {calculate_price_with_tax(1000)}")

# 2. When the argument is specified (Specified value 0.08 is used)
print(f"Reduced tax rate: {calculate_price_with_tax(1000, 0.08)}")

Output:

1000 yen with tax: 1100
Reduced tax rate: 1080

Definition Order Rule

When using default arguments, arguments without default values (mandatory arguments) must be written first, followed by arguments with default values. Failing to follow this order will result in a SyntaxError.

# Error Example
# Mandatory argument 'y' follows default argument 'x'
# def invalid_func(x=1, y):
#     print(x, y)
# SyntaxError: non-default argument follows default argument

The Pitfall: Mutable Objects as Default Values

This is the most important point. If you set a mutable object like a list (list) or dictionary (dict) as a default argument, it can cause unexpected behavior.

Problematic Code Example

Let’s create a function to add a task, setting an empty list [] as the default task list.

def add_task(task_name, task_list=[]):
    """
    Function to add a task to a list and return it.
    (BAD EXAMPLE: Using a list as a default value)
    """
    task_list.append(task_name)
    return task_list

# 1st Call
print(f"1st: {add_task('Check Email')}")

# 2nd Call (Expecting a new list to be created, but...)
print(f"2nd: {add_task('Meeting')}")

# 3rd Call
print(f"3rd: {add_task('Write Report')}")

Output:

1st: ['Check Email']
2nd: ['Check Email', 'Meeting']
3rd: ['Check Email', 'Meeting', 'Write Report']

Why Does This Happen?

In Python, default values for functions are created (evaluated) only once when the function is defined. Therefore, when you write task_list=[], that single list object is created in memory, and the same list object is reused every time the function is called. As a result, the content added in previous calls remains.


Safe Implementation: Use None

The standard way (idiom) to avoid this problem is to set the default value to None and check inside the function “if it is None, create an empty list.”

def add_task_safe(task_name, task_list=None):
    """
    Safe implementation: Set default value to None
    """
    # Create a new list only if the argument is omitted (is None)
    if task_list is None:
        task_list = []
    
    task_list.append(task_name)
    return task_list

# 1st Call
print(f"1st: {add_task_safe('Check Email')}")

# 2nd Call
print(f"2nd: {add_task_safe('Meeting')}")

# 3rd Call
print(f"3rd: {add_task_safe('Write Report')}")

Output:

1st: ['Check Email']
2nd: ['Meeting']
3rd: ['Write Report']

With this approach, task_list = [] is executed every time the function is called without the argument, generating a new list each time.


Summary

  • Default arguments allow you to make arguments optional.
  • Default arguments must be defined after mandatory arguments.
  • Do not use mutable objects (like lists or dicts) as default values (because the same object is reused).
  • If you want to use a mutable type as a default, use None and initialize it inside the function with if arg is None: arg = [].
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次