【Python】デフォルト引数にリストを使うときの注意点

自分が知らなかったのでメモ

関数のデフォルト引数にリストを設定した時、デフォルト引数のリストの内容は再度実行したタイミングでも前の内容を保持します。

def sample(a, b=[]):
  b.append(a)
  return b

print(sample('test'))

['test']

print(sample('test'))

['test', 'test']

公式ドキュメントを読む

公式ドキュメントを当たると、次のように書いてあります。

デフォルト引数値は関数定義が実行されるときに左から右へ評価されます。 これは、デフォルト引数の式は関数が定義されるときにただ一度だけ評価され、同じ "計算済みの" 値が呼び出しのたびに使用されることを意味します。この仕様を理解しておくことは特に、デフォルト引数値がリストや辞書のようなミュータブルなオブジェクトであるときに重要です: 関数がこのオブジェクトを変更 (例えばリストに要素を追加) すると、このデフォルト値が変更の影響を受けてしまします。一般には、これは意図しない動作です。このような動作を避けるには、デフォルト値として None を使い、この値を関数本体の中で明示的にテストします。例えば以下のようにします:

def whats_on_the_telly(penguin=None):
    if penguin is None:
        penguin = []
    penguin.append("property of the zoo")
    return penguin

ミュータブルなオブジェクトを使う時に注意しなければいけないので、辞書も気をつけなければいけない対象です。 デフォルト値にNoneを使うことでも、この問題を回避できることが書いていました。

デフォルト引数を使うタイミング

そもそもデフォルト引数を使うタイミングがあまり想像できなかったので周りのエンジニアに聞いたところ、既存の関数に引数を追加したい時に使うと教えてもらいました。言われれば、呼び出し元に影響を与えず関数の中を変えられますので当然ですね。