引数の数が決まっていないときはどうする?
ほとんどの関数は、受け取る引数の数があらかじめ決まっています。でも、ときには「もっと柔軟に受け取りたい」という場面が出てきます。たとえば、メッセージをいくつでも受け取れるロガー、受け取った引数をそのまま別の関数に渡すラッパー関数、呼び出し側がどのオプションを指定してくるか分からないグラフ描画関数などです。
こうしたケースのために、Python では引数リストで使える2つの特別な記法 *args と **kwargs が用意されています。
*args は位置引数をまとめて受け取る
アスタリスク1つの *args は、「余分な位置引数をすべてタプルにまとめてね」という意味になります。
関数の内部では、args はごく普通のタプルとして扱えます。for ループで回したり、インデックスでアクセスしたり、len() に渡したり、スライスを取ったりと、タプルにできる操作はひと通り使えます。
実際のコードでは、*args は名前付きの引数と一緒に使うことがほとんどです。
first が最初の引数を受け取り、それ以降はすべて *rest がタプルにまとめてくれます。
**kwargs でキーワード引数をまとめて受け取る
アスタリスク2つを使えば、キーワード引数に対して同じことができます。こちらは辞書(dict)としてまとめられます。
describe の内部では、kwargs はただの辞書として扱えます。キーはキーワード名の文字列です。
*args と **kwargs を組み合わせて使う
同じ関数の中で両方を一緒に使うこともできます。書く順番は *args を先、**kwargs を後にするのが決まりです。
引数を並べる順番は、先頭から順に次のようになります。
- 通常の位置引数(必須のもの、またはデフォルト値を持つもの)
*args- キーワード専用引数(
*argsの後ろに置いた引数は、必ずキーワードで渡す必要があります) **kwargs
title は最初の位置引数を受け取ります。残りの位置引数はすべて tags に入ります。draft は *tags の後にあるので、キーワード引数として渡すしかありません。それ以外のキーワード引数はまとめて metadata に収まります。
呼び出し側での * と ** によるアンパック
実はこのアスタリスクは 逆向き にも使えます。シーケンスや辞書を展開して、関数呼び出しの引数として渡せるんです。
これは引数の転送(*args・**kwargs)にめちゃくちゃ便利です:
wrapped 側は log がどんな引数を受け取るかを知らなくて大丈夫です。全部まとめて受け取って、そのまま流すだけ。このパターンはデコレータ(少し進んだトピックです)やラッパー関数で本当によく出てきます。
*args と **kwargs を使うべきでない場面
便利だからといって何にでも使いたくなりますが、注意点が2つあります。
関数が何を期待しているのか見えなくなる
コードベース中の関数が軒並み def f(*args, **kwargs) になっていると、呼び出す側はどんな引数を渡せばいいのか全く分かりません。できる限り名前付きの引数を使い、*args/**kwargs は本当に可変長にしたい入力や、純粋な引数転送のときだけに留めましょう。
エラーメッセージがあいまいになる
キーワード名をタイプミスしても、呼び出した瞬間に「unexpected keyword argument」と怒られる代わりに、関数の奥深くで静かに None になっていたり KeyError が飛んだりします。名前付き引数にしておけば、ずっと分かりやすいフィードバックが得られます。
基本方針としては、まずは名前付き引数を使う。*args/**kwargs は関数が本当に柔軟性を持つべきとき、もしくは別の呼び出し先に引数を転送するときだけ使う、と覚えておきましょう。
ちょっとした実例
デフォルト値をいくつか付けた上で、サードパーティの関数をラップするプロット系ヘルパーの例を見てみましょう。
*values があれば呼び出し側は好きな数だけ値を渡せますし、**style は余分な設定をまとめて受け取ってくれるので、すべてのオプションを個別の引数として定義する必要がありません。柔軟ではあるものの、中身の処理を見れば style からどのキーを読んでいるかが一目瞭然なので、ブラックボックスにもなりません。
まとめ
*argsは余った位置引数をタプルにまとめる。**kwargsは余ったキーワード引数を辞書にまとめる。- 呼び出し側では、
*seqと**dictを使えば逆方向にアンパックできる。 - 引数の順序は「通常の引数 →
*args→ キーワード専用引数 →**kwargs」の並びを守る。 - 使いすぎは禁物。名前付き引数で書けるなら、そちらのほうが読みやすい。
次回は lambda を取り上げます。その場でサッと書ける使い捨ての小さな関数を作るための構文です。
よくある質問
Pythonの*argsとは何ですか?
*args は、余った「位置引数」をまとめてタプルとして受け取る仕組みです。例えば def f(*args): と定義しておけば、f(1, 2, 3) と呼び出したときに args は (1, 2, 3) になります。args という名前はあくまで慣習で、別の名前でも動きますが、Pythonコミュニティではほぼ全員が *args を使っています。
Pythonの**kwargsとは何ですか?
**kwargs は、余った「キーワード引数」を辞書としてまとめて受け取ります。def f(**kwargs): と書いておけば、f(name='Ada', age=30) と呼び出したときに kwargs は {'name': 'Ada', 'age': 30} になります。*args と **kwargs を組み合わせれば、どんな引数の組み合わせでも受け取れる関数が書けます。
名前は必ず args と kwargs にしないといけませんか?
いいえ、意味を持っているのは頭についた * と ** だけで、名前自体は何でも構いません。*values や **options でもまったく同じように動きます。ただ、Pythonのコードでは args と kwargs がほぼ標準的な慣習として定着しているので、特別な理由がない限りはそのまま使うのがおすすめです。