こんにちは、吉政創成 菱沼です。
今回もPythonエンジニア育成推進協会のPython 3 エンジニア認定実践試験の主教材「Python実践レシピ/技術評論社」を使って学習中です。
関数にデータを受け渡すのに利用される引数。引数にはいくつかの種類があり、前回は位置引数とキーワード引数について学びました。今回はデフォルト値付き引数です。
デフォルト値付き引数とは何か
※Pythonでは関数定義時に使う引数を仮引数(parameter)とし、関数呼び出し時に渡す引数を実引数(argument)と呼ぶそうです。書籍もそれに合わせて記述されています。
デフォルト値付き引数は、関数の引数にあらかじめ値が設定された仮引数のことで、「引数名=デフォルト値」と記述されます。
関数を呼び出した際、実引数を省略すると、デフォルト値が使用されます。逆に、実引数を指定した場合には呼び出し時に指定した値が使用されます。
というわけで、ここで書籍のサンプルコードを確認してみます。
P.53
def sample_func(param1, param2=2, param3=3):
print(f'{param1}, {param2}, {param3}')
sample_func(1) # 必須の引数のみ与える
1, 2, 3
sample_func(1, 20) # 1つのオプション引数を与える
1, 20, 3
sample_func(1, param3='hoge')
1, 2, hoge
sample_func(10, 20, 30) # すべての引数を与える
10, 20, 30
sample_funcには3つの仮引数の内、2つ目と3つ目にデフォルト値が設定されています。
なので、1つ目の実引数は必須ですが、2つ目と3つ目には実引数を渡さなくても、オプションで設定されたデフォルト値が使用されるため、エラーにはなりません。
デフォルト値を設定するのは「後」
デフォルト値を設定しない仮引数は必ず、デフォルト値を設定する仮引数より先に書いておく必要があります。もしデフォルト値を設定した後に、設定しない仮引数を設定してしまうとエラーが出ます。

デフォルト値に指定できる値
デフォルト値として指定するのは、文字列、数値、タプルなどの変更不可(イミュータブル)なオブジェクトが推奨されているようです。
とはいえ、リストや辞書などの変更可能(ミュータブル)なオブジェクトも設定することはできます。
ただ、デフォルト値は関数を定義したときに1回だけ評価される仕様のため、前回の値が残ってしまうなどの意図しない挙動になることがあるそうです。
こんな感じに。

参考:
デフォルト引数値は関数定義が実行されるときに左から右へ評価されます。 これは、デフォルト引数の式は関数が定義されるときにただ一度だけ評価され、同じ “計算済みの” 値が呼び出しのたびに使用されることを意味します。この仕様を理解しておくことは特に、デフォルト引数値がリストや辞書のようなミュータブルなオブジェクトであるときに重要です
Python公式ドキュメント 8.7 関数定義
なので、もしミュータブルなオブジェクトを使う場合には、デフォルト値にNone(変更されない特別な値)を設定し、関数内で初期化する方法が一般的とのこと。
これを先ほどのコードで試してみるとこんな感じになります。

ちなみに、キャッシュの保持や状態保持を目的として、この仕様を意図的に使うケースもあるそうなので、頭の片隅に置いておくといいのかなと思います。
デフォルト値付き引数×キーワード引数 でつかってみよう
ではここで。
せっかくなので、デフォルト値付き引数と、前回学習したキーワード引数を合わせて使ってみたいと思います。
デフォルト値付き引数とキーワード引数を組み合わせると、必要な値だけを上書きできる柔軟な関数を定義できるのと、コードを読みやすくしてくれるという効果があるとのこと。
関数定義の時点では、デフォルト値付き引数は後ろに書きます。そして、関数呼び出しの時点では、位置引数を先に、キーワード引数を後に書きます。 また、キーワード引数の後に位置引数を置くこともできません。

こんな感じ。
また、def fuguta_user(name, *, age, city=”東京”, member=”家族”):のように、途中で*(アスタリスク)を入れると、これ以降の引数をキーワード引数でしか渡せないようにするということもできるそうです。
それではきりが良いので今回はこちらで終了です。
お付き合いいただきありがとうございました。
実践試験について知りたい方は以下をご覧ください。
●Python3エンジニア認定実践試験
