Pythonでは関数(やメソッド)を定義する際に、引数のデフォルト値を設定可能です。デフォルト引数を設定すると、関数呼び出し時に引数が省略した場合に、設定したデフォルト値が使用されます。
def foo(text='おはよう'):
print(text)
foo()
# おはよう
foo(text='こんにちは')
# こんにちは
上記の関数ではデフォルト引数として、textにおはよう
を設定しました。そのため、関数呼び出し時に引数を省略した場合は、デフォルト値が使われ、引数を明示的に指定した場合は、指定した引数の値が使用されます。
デフォルト引数は、デフォルトのパラメータを設定しておく場合など便利に使えます。
デフォルト引数の注意点 #
このように便利なデフォルト引数ですが、大きな注意点があります。 それは、デフォルト引数にリストや辞書などのミュータブルなオブジェクトを指定してはいけないということです。
なぜなら、Pythonのデフォルト引数の値は関数呼び出しのたびに初期化されず、関数定義にのみ評価されるからです。そのため、ミュータブルなオブジェクトをデフォルト引数に指定すると何度も同じオブジェクトが呼び出されます。 デフォルト引数で呼び出されたオブジェクトに対して変更を加えると、次回関数を呼び出された際に、変更が加えらたオブジェクトが呼びだされることになります。
デフォルト引数にミュータブルなオブジェクトを指定した際の挙動 #
以下にデフォルト引数にリストを指定した関数の例を示します。
def foo(text_list=[], text='おはよう'):
text_list.append(text)
print(text_list)
foo()
# ['おはよう']
foo()
# ['おはよう', 'おはよう']
foo()
# ['おはよう', 'おはよう', 'おはよう']
foo(text_list=[])
# ['おはよう']
foo()
# ['おはよう', 'おはよう', 'おはよう', 'おはよう']
上記の関数は、引数を指定しないと、関数が呼ばれるたびに同じオブジェクトをデフォルト引数として利用しますので、呼び出すたびに同じリストに値をappendしてしまい、出力結果が変化します。
注意点への対策 #
ではどうすれば良いかというと、デフォルト引数にミュータブルなオブジェクトを指定するのではなく、None
を指定して関数内でNone
の場合、空のミュータブルなオブジェクトを指定します。
def foo(text_list=None, text='おはよう'):
text_list = text_list or [] # Noneの場合に空のリストを指定
text_list.append(text)
print(text_list)
foo()
# ['おはよう']
foo()
# ['おはよう']
foo()
# ['おはよう']
foo(text_list=[])
# ['おはよう']
foo()
# ['おはよう']
上記のように記述すると、引数が指定されていなくても関数呼び出しの際に、オブジェクト(上記の関数であれば空のリスト)が初期化されます。