Python は引数にデフォルト値を指定できますが、ここでの =演算子は関数定義時にのみ呼び出され、以降は呼ばれることがありません。
C言語をご存じの方なら static変数の挙動を思い浮かべれば分かりやすいと思います。
具体例を示します。
# デフォルト値が[] >>> def func(a=[]): ... a.append(1) ... print(a) ... # a=[] は関数定義時に一度だけ実行される。 # 以降 a は継続して使用される。 >>> func() [1] >>> func() [1, 1] >>> func() [1, 1, 1]
この動作はかなり非直感的です。また、static変数的な動作は Python の思想とも合いません。
この問題は デフォルト値が mutable である時に起きやすいのですが、以下の例でも発生します。デフォルト値は関数定義時に確定するという点に注意して下さい。
>>> import time >>> def print_time(t=time.time()): # 関数定義時に t が確定 ... print(t) ... >>> time.time() # 現在時刻 1447445703.360414 >>> print_time() # 定義時の時刻 1447445695.017109 >>> print_time() 1447445695.017109 >>> print_time() 1447445695.017109
この問題の対策としては、デフォルト値を None にしておき、引数が None であれば関数の冒頭で改めて値を代入する、という方法が知られています。
上で挙げた2つの関数に対策を施すと、それぞれ以下のようになります。
>>> def func(a=None): ... # Noneなら新規空リスト ... a = [] if a is None else a ... ... a.append(1) ... print(a) ... >>> def print_time(t=None): ... # Noneなら現在時刻 ... t = time.time() if t is None else t ... ... print(t) ...
上記のような対策方法があるわけですが、これはいかにも回避策といった感じです。根本的には「引数のデフォルト値は関数定義時のみ代入される」という仕様自体がイマイチなように思います。
0 件のコメント:
コメントを投稿