Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
83
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

⚠️Pythonのデフォルト引数値に気をつけましょう⚠️

ちゃお・・・†

最近Pythonのデフォルト引数値による意図せぬ挙動に悩まされたので、同じ過ちを繰り返さぬようここで情報を共用したいと思います。こちらの環境はPython 3.7.7と3.8.3です。

デフォルト引数値とは

下記コードのうち dt=datetime.now()を指します。

from datetime import datetime


def show_second(dt=datetime.now()):
    print(dt.second)

Pythonのデフォルト引数値の罠

先ほどのコードを、 show_second 関数を一度呼び出し、三秒後にまた show_second 関数を呼び出すようにいじってみました。

import time
from datetime import datetime


def show_second(dt=datetime.now()):
    print(dt.second)

show_second()  #=> 23
time.sleep(3)
show_second()  #=> 23

すると、なんということでしょう!三秒間sleepしたにも関わらず二度目の show_second 関数呼び出し時にプリントされる値が三秒前と同じでした…!?時が止まった?ザ・ワールド???新手のスタンド使いか???

Pythonのデフォルト引数値の挙動

さて、これはどういうことかとPythonのドキュメントを読んでみたところ、下記の記述がありました。

デフォルト引数値は関数定義が実行されるときに左から右へ評価されます。 これは、デフォルト引数の式は関数が定義されるときにただ一度だけ評価され、同じ "計算済みの" 値が呼び出しのたびに使用されることを意味します。
from: https://docs.python.org/ja/3/reference/compound_stmts.html#function-definitions

つまり、関数定義時にデフォルト引数値は一度評価され、その結果がメモリーに保存されて、以降はその関数を何回呼び出してもデフォルト引数値を利用する場合は関数定義時の評価結果を使用するという仕組みになっているようです。

なので、datetime.now() のようなcallする度に違う結果を出すもの and/or リアルタイム性が求められるものをデフォルト引数値として用いるのは危険です⚠️

同様にデフォルト引数値にリストや辞書を指定したときも気をつける必要があるようです。(Pythonの関数でのデフォルト引数の使い方と注意点 | note.nkmk.me)

Pythonのデフォルト引数値の対策

それではどうしたらいいかというと、デフォルト引数値に None を設定して、None であれば本来デフォルト引数値として設定したかった値を代入するという風にするのが良いそうです。

以下example codeです。

import time
from datetime import datetime


def show_second(dt=None):
    if dt is None:
        dt = datetime.now()
    print(dt.second)

show_second()  #=> 23
time.sleep(3)
show_second()  #=> 26

そんなわけでPythonのデフォルト引数値に気をつけようというお話でした。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
83
Help us understand the problem. What are the problem?