書き換え可能オブジェクトを関数の引数のデフォルト値にするときの注意点

Pythonの関数の引数にはデフォルト値を設定することができて、デフォルト値が設定されている引数は呼び出し時に省略することができる。それはいいんだけど、そのデフォルト値に書き換え可能オブジェクトを設定したときには注意が必要だ。関数の中でこの引数を書き換えてしまうと、奇妙なことが起こる。たとえば次のようなコードの場合だ。

def foo(a = []):
    a.append("bar")
    print a

foo()
foo()
foo()
foo([1,2,3])
foo()

関数fooは省略可能な引数aをとり、aが省略されたときには空のリストを代入するようになっている。ところが、Pyhtonでは引数のデフォルト値の代入は関数が初めて呼び出されたときだけにおこり、しかも以後その値(オブジェクト)が引き継がれる。実行してみよう:

^o^ > python default_arg.py
['bar']
['bar', 'bar']
['bar', 'bar', 'bar']
[1, 2, 3, 'bar']
['bar', 'bar', 'bar', 'bar']

関数fooを全部で5回呼び出してるけど、引数を与えているのは4回目だけでほかは省略している。1回目の呼び出しの結果は簡単に予想できるとおりだ。省略された引数の変わりに空のリストが使われて、関数の中で’bar’が追加されている。2回めの呼び出しの結果は予想と違う。予想では1回目と同じ結果になりそうなものなのに、’bar’が2つある。これは、前回呼び出されたときのオブジェクトを使いまわしているせいだ。1回目の呼び出しで’bar’を1つ追加し、2回目の呼び出しでもう1つ追加している。結果、’bar’が2つあるってわけ。3回目の呼び出しも同様。4回目の呼び出しでは引数を与えているので予想通りの結果になっているけど、5回目の呼び出しではやっぱり’bar’が増えている。

これはないわぁ。何でこんな仕様になってるのか知らないけど、これを避けるためには実質的に引数を省略しないことしかないんじゃないかな。これはうれしくないないなぁ。

カテゴリー: Python パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください