デフォルト引数の破壊

デフォルト引数を使用する際の注意点

前のページで、関数定義で引数のデフォルト値を設定できることを説明しましたが、1点重要な注意点があります。まずは以下のサンプルを見てください。

def sample(x, arg=[]):
    arg.append(x)
    return arg

print(sample(1)) # [1]
print(sample(2)) # [1, 2] !?
print(sample(3)) # [1, 2, 3] !!??

引数のリストに0を加えるsample関数を3回呼び出していますが、2回め以降は設定されていないものが戻り値に加えられてしまっています。これはデフォルト引数の評価は最初の1回しか行われないため、appendのような破壊的な操作を行うと、デフォルト引数の値が1回めの呼び出しで[1]に、2回めの呼び出しで[1, 2]に書き換わってしまうからです。

対策として、デフォルト引数にはイミュータブルなものを使用することで破壊されないようにし、if文等で引数が空の場合の初期値設定の処理を加えます。

def sample(x, arg=None):
    if arg is None:
        arg = []

    arg.append(x)
    return arg

print(sample(1)) # [1]
print(sample(2)) # [2]
print(sample(3)) # [3]