数値や真偽値を位置だけで並べると、係数とオフセット、上書き可否などを取り違えやすい。意味を明示して渡してほしい引数は、定義の*より後ろへ置いてキーワード専用にする。位置で渡すことを禁止できるため、読みやすさのお願いだけに頼らず、関数の呼び出し方として制約を表せる。
名前が見える呼び出しにする
例えばconvert(10, 0.1, 2)という呼び出しでは、0.1と2が何を意味するかを関数定義まで見に行く必要がある。convert(10, factor=0.1, offset=2)なら、換算係数とオフセットがその場で分かる。位置の入れ替えによる誤りも起こしにくくなる。
ただし、普通の引数にもキーワードを付けて呼ぶことはできる。キーワード専用引数を使う意味は、付けずに呼ぶ形を許可しないことにある。関数を多くの場所から使う場合や、複数の数値が似た意味を持つ場合に役立つ。
必須キーワードと既定値を組み合わせる
example.py
def convert(value, /, *, factor, offset=0.0):
return value * factor + offset
result = convert(10, factor=0.1, offset=2)
print(result)
assert result == 3.0
assert convert(10, factor=0.1) == 1.0
invalid_calls = [
lambda: convert(10, 0.1),
lambda: convert(10),
lambda: convert(value=10, factor=0.1),
]
for call in invalid_calls:
try:
call()
except TypeError:
print("TypeError")
else:
raise AssertionError("An invalid call was accepted")
実行結果
3.0
TypeError
TypeError
TypeError
factorは既定値を持たないので、毎回キーワードで渡す必要がある。offsetは省略すると0.0になる。*より後ろだからといって必ず省略可能になるわけではなく、必須かどうかは既定値の有無で決まる。
位置専用引数の意味も確認する
valueの後ろの/は、その前にある引数を位置専用にする記号である。この例ではvalue=10という渡し方を受け付けない。valueという内部の名前を呼び出し側のキーワードとして固定したくない場合などに使える。位置専用引数の構文はPython 3.8以降で利用できる。
ただし、すべての関数に/を付ける必要はない。利用者が入力名を指定した方が読みやすいAPIなら、通常の位置またはキーワード引数のままにすればよい。*と/は別々の制約であり、どちらか片方だけを使うこともできる。
| 位置 | 渡し方 |
|---|---|
| /より前 | 位置だけ |
| /と*の間 | 位置またはキーワード |
| *より後 | キーワードだけ |
型や値の意味までは保証しない
キーワード専用にしても、factorに文字列を渡すことや、単位を取り違えることまで自動で防げるわけではない。必要なら型や範囲の検証を関数本体で行う。呼び出し方の制約と、入力値の妥当性は別の問題である。
特にoverwrite=Trueのような重要な選択肢は、名前が見えるだけでも確認しやすい。ただし、Trueを指定すれば何が上書きされるかという説明や、安全な既定値の選択は引き続き必要になる。シグネチャだけで処理のすべての意味が伝わるとは考えないようにしたい。
既存関数を変更するときは呼び出し側も確認する
すでに位置引数を使うコードがある関数へ後から*を追加すると、そのコードはTypeErrorになる。便利だからといって無条件に変更せず、利用箇所を調べ、キーワード付きの呼び出しへ移行してから制約を強める。公開APIなら互換性の扱いも考える必要がある。
また、キーワード専用の名前を変えることも、利用側の呼び出しへ影響する。位置だけを許す引数と、名前を公開する引数のどちらにするかは、今後の変更にも関係する。意味が長く安定しそうなオプション名を選ぶと扱いやすい。
意図しない呼び出しが止まることを確かめる
正常な計算結果だけでなく、係数を位置で渡す、省略する、位置専用の値をキーワードで渡すという誤用も確認する。この記事では例外の文言全体を固定せず、TypeErrorになることを確かめた。詳細なメッセージはPythonの版によって変わることがある。
短い計算関数でも、主要な入力は位置で、動作を変える条件はキーワードで、という分け方にすると使いやすい。最終的には利用者が実際に書く呼び出しを見て、読み取りやすく誤用しにくいシグネチャを選ぶのがよい。
動作確認と参考資料
掲載例はLinux・CPython 3.12.14で動作確認した。OS固有のコマンドや環境ごとに変わるパスは、本文中の条件を確認して使ってほしい。
