Pythonの仮引数の扱いの注意点
注意すべきは、仮引数のデフォルト値として、リストなどを指定した時だ。
定義する関数内でその変数に書き込みをすると、2度目以降にその影響が残る。
この動作を理解するポイントは、def文による関数定義は、perlの関数定義のような宣言文ではなく、pythonでは実行文だということだ。
実行文であるゆえに、デフォルト値の生成は、def文の実行時に行われる。関数呼び出し時にデフォルト値が生成されるわけではない。
ロジックを可視化したもの
Python Tutor code visializerで、このロジックを示す例を可視化した。
それを見るには、下記リンクをクリックして欲しい。
例にしたコードは、下記のとおり。
def func(a,b=[1]):
c = a+b[0]
b[0]=3
return c
func(1)
func(1,[2,3])
func(1)
これを可視化したもので順に実行すると、以下が分かる。
- Step 2の段階では、変数bのデフォルト値のリストが生成済みである
- Step 3の関数呼び出し時には、変数bはその生成済みのリストを指す
- Step 6でそのリストの中身を修正している
- Step 9の関数呼び出し時は、変数bの値を引数で渡しているゆえ、変数bは別のリストを指す
- Step 15の関数呼び出し時は、Step 6で修正したリストを変数bは指すので、返り値が1回目の呼び出しと異なるという状態につながる