2.15. 引数

関数はいくつかの方法で呼び出すことができ、そのパラメータもいくつかの形で宣言できます。組み合わせは最初は手ごわく見えますが、実際にはほぼすべてを 3、4 のパターンでカバーできます。

2.15.1. 位置引数とキーワード引数

最も単純な呼び出しは、引数を位置で渡します -- 最初の値が最初のパラメータに、2 番目の値が 2 番目のパラメータに、というように渡されます。

def rect(x, y, w, h):
    return (x, y, w, h)

rect(10, 20, 100, 50)

同じ呼び出しを、各パラメータを明示的に名前で指定して、引数をキーワードで渡すこともできます。

rect(x=10, y=20, w=100, h=50)

キーワード引数は順序に依存せず、入力量は増えますが、呼び出しが自己説明的になります。位置引数とキーワード引数は 1 回の呼び出しで混在させることができますが、すべての位置引数はキーワード引数より前に置かなければなりません。

rect(10, 20, w=100, h=50)         # OK
rect(x=10, 20, 100, 50)           # SyntaxError

2.15.2. デフォルト値

パラメータには、呼び出し側が値を指定しなかった場合に使うデフォルト値を宣言できます。

def greet(name, greeting="hello"):
    print(greeting, name)

greet("Alice")                    # hello Alice
greet("Alice", "hi")              # hi Alice
greet("Alice", greeting="hey")    # hey Alice

デフォルトを持つパラメータは、def 行において、デフォルトを持たないパラメータより後ろに置かなければなりません。

警告

デフォルト値は、毎回の呼び出しではなく、def が実行されたときに 1 度だけ評価されます。ミュータブルなデフォルト([]{})を使うと、デフォルトを取るすべての呼び出しで同じオブジェクトが共有されてしまいます。代わりに、番兵として None を使ってください。

def append_to(item, target=None):
    if target is None:
        target = []
    target.append(item)
    return target

2.15.3. 可変長:*args**kwargs

* を前に付けたパラメータは、残りの位置引数をすべて tuple にまとめます。** を前に付けたパラメータは、残りのキーワード引数をすべて dict にまとめます。慣例的な名前は argskwargs ですが、任意の識別子が使えます。

def report(label, *values, **options):
    print(label, values, options)

report("temps", 21, 22, 23, unit="C", precision=1)

出力:

temps (21, 22, 23) {'unit': 'C', 'precision': 1}

両方を必要とする関数はめったにありません。最も一般的な用途は、ラッパーから内部の呼び出しへ引数を転送することです。

def log_and_call(func, *args, **kwargs):
    print("calling", func.__name__)
    return func(*args, **kwargs)

呼び出し側での鏡像のような構文は、イテラブルを位置引数に(*)、または dict をキーワード引数に(**)アンパックします。

point = (10, 20, 100, 50)
rect(*point)                      # same as rect(10, 20, 100, 50)

kwargs = {"x": 10, "y": 20, "w": 100, "h": 50}
rect(**kwargs)                    # same as rect(x=10, y=20, ...)

2.15.4. キーワード専用パラメータ

パラメータリスト内で(名前に付かない)* 単独は、それ以降のすべてのパラメータをキーワード専用にします -- 呼び出し側は名前を使わなければなりません。

def crop(buffer, *, x, y, w, h):
    ...

crop(buffer, x=0, y=0, w=100, h=100)   # OK
crop(buffer, 0, 0, 100, 100)           # TypeError

これは、ブール値のフラグや、呼び出し側で値だけを書いても何を意味するか分かりにくいその他の引数に使ってください。