Pythonでは、関数には4種類のパラメータを宣言できます:位置指定、キーワード、位置指定のみ、キーワードのみ。これらの違いは、関数を呼び出す際の値の渡し方に影響を与えます。
/記号の前に宣言され(Python 3.8+)、名前で指定することはできません。*の後に宣言され、キーでのみ指定できます。# すべてのタイプの例 def func(a, b, /, c, *, d, e): print(a, b, c, d, e) func(1, 2, 3, d=4, e=5) # OK # func(a=1, b=2, 3, d=4, e=5) # エラー:a, bは位置指定のみ
SyntaxErrorまたはTypeErrorが発生します。*argsは追加の位置指定引数を集め、**kwargsはキーワード引数を集めます。関数の宣言は何が違うか:
def f(a, b, c): ... def f(a, b, c=1): ... def f(a, b=1, c=2): ... def f(a=1, b=2, c=3): ...
そして、これらすべての関数は位置指定引数とキーワード引数の両方で呼び出せるのは本当か?
def f(a, b, c):という関数は、すべての引数が必須であるため、キーワード引数のみで呼び出すことはできません。def f(a, b, /, c):として宣言されている場合、aとbは位置指定のみで指定できます。def f(a, b, c=10): print(a, b, c) f(1, 2) # OK, c=10がデフォルト f(a=1, b=2, c=3) # OK # ですが: def f(a, b, /, c=10): ... f(1, 2) # OK f(a=1, b=2, c=3) # エラー!aとbは位置指定のみ
物語
ある開発者が、名前でのみパラメータを受け取るべき関数を実装したが、*を宣言するのを忘れてしまい、ユーザーが位置で誤ってパラメータを渡すことができた。その結果、ロギングが誤って行われ、追跡が難しいエラーが発生した。
物語
REST APIプロジェクトでは、引数の順序について明示的に合意が行われておらず(*argsを使い、名前による制限をしていなかった)、新しいクライアントバージョンを導入した後にリクエストが機能しなくなった。これは、argsがズレたためである。明示的な*を導入し、キーワード引数のみを指定することによって修正した。
物語
大規模な企業プロジェクトでは、関数にデフォルト値を持つ新しいパラメータが追加されたが、位置指定引数による誤った呼び出しにより、古いコードが他のパラメータに値を挿入し、データが不適切に処理された。パラメータをキーワードのみとして指定する必要があった。