Python **kwargsの使い方|引数の順番・エラーメッセージ・速度を実測で確認
**kwargs はキーワード引数をまとめて受け取るための書き方です。受け取った中身は辞書(dict)になります。
この記事のコードと出力・エラーメッセージは、すべて Python 3.9.6 で実際に実行して確認したものです。確認日は2026年9月28日です。バージョンによってエラーメッセージの文面が変わる箇所は、そのつど注記します。
**kwargs とは|受け取るのは辞書
関数の引数に ** を付けると、呼び出し側が書いたキーワード引数が1つの辞書にまとめて入ってきます。名前は kwargs でなくても構いません(**options でも動きます)。慣習として kwargs が使われます。
def f(**kw):
return type(kw).__name__, list(kw)
print(f(b=1, a=2, c=3))
# 出力: ('dict', ['b', 'a', 'c'])
渡した順番がそのまま保たれます。上の例で a より先に b が来ているのは、呼び出し側がその順で書いたからです。これは Python 3.6 で仕様として決まったもの(PEP 468)で、辞書のキー順に依存した処理を書いても壊れません。
なお **kwargs で受け取った引数はキーワードでしか渡せません。位置引数として渡すとエラーになります。
f(1)
# TypeError: f() takes 0 positional arguments but 1 was given
引数を書く順番には決まりがある
この順番以外では書けません。順番を間違えると実行前に SyntaxError になります。
def g(a, b=2, *args, c, d=4, **kw):
return dict(a=a, b=b, args=args, c=c, d=d, kw=kw)
print(g(1, 9, 7, 8, c=3, z=5))
# 出力: {'a': 1, 'b': 9, 'args': (7, 8), 'c': 3, 'd': 4, 'kw': {'z': 5}}
| 位置 | 種類 | 上の例 |
|---|---|---|
| 1 | 通常の引数 | a |
| 2 | デフォルト値つきの引数 | b=2 |
| 3 | *args(余った位置引数) |
*args |
| 4 | キーワード専用引数(*args の後ろは必ずこれになる) |
c と d=4 |
| 5 | **kwargs(余ったキーワード引数) |
**kw |
見落としやすいのは4番です。*args より後ろに書いた引数はキーワードでしか渡せなくなります。上の例の c はデフォルト値がないので、省略すると次のエラーになります。
g(1)
# TypeError: g() missing 1 required keyword-only argument: 'c'
順番を守らない定義は、実行される前に落ちます。実際のメッセージはこうです。
def h(**kw, a): pass # SyntaxError: invalid syntax
def h(**kw, *args): pass # SyntaxError: invalid syntax
def h(*, **kw): pass # SyntaxError: named arguments must follow bare *
辞書を ** で渡す(アンパック)
呼び出し側でも ** が使えます。辞書のキーがそのまま引数名になります。
def base(x, y=0):
return x + y
d = {'x': 1, 'y': 2}
print(base(**d)) # 3
【見落とされがち】識別子として使えないキーも渡せる
これは意外な挙動です。content-type のようにハイフンを含む文字列はPython の変数名にできませんが、** で渡すことはできます。
def f(**kw):
return kw
r = f(**{'content-type': 'text/html', 'x-api-key': 'abc'})
print(r) # {'content-type': 'text/html', 'x-api-key': 'abc'}
print(r['content-type']) # text/html
# ただし仮引数名には使えない
def g(content-type): pass # SyntaxError
HTTPヘッダーのように、ハイフン区切りの名前をそのまま扱いたいときに効きます。受け取る側は kw['content-type'] と辞書として読みます。
一方でキーが文字列でない場合は通りません。
f(**{1: 'x'})
# TypeError: keywords must be strings
実際に出るエラーメッセージ
エラー文面を覚えておくと原因の切り分けが速くなります。以下は Python 3.9.6 で実測したものです。
| やってしまうこと | 出るエラー |
|---|---|
| 定義にない名前を渡した | TypeError: only_a() got an unexpected keyword argument 'b' |
位置引数とキーワードで同じ引数を二重に渡したp(1, a=2) |
TypeError: p() got multiple values for argument 'a' |
2つの辞書に同じキーがあったp(**{'a':1}, **{'a':2}) |
TypeError: p() got multiple values for keyword argument 'a' |
| キーワード専用引数を省略した | TypeError: g() missing 1 required keyword-only argument: 'c' |
文字列でないキーを ** で渡した |
TypeError: keywords must be strings |
2番目と3番目は文面が1語だけ違います。「for argument」なら位置引数とぶつかっていて、「for keyword argument」なら辞書どうしがぶつかっています。ここを読み分けると、どちらを直せばよいかがすぐ分かります。
Python 3.10以降はエラーメッセージに関数の修飾名が入る形に変わっています。文面が上と完全に一致しない場合はバージョン差です。エラーの種類(TypeError)と原因の見分け方は同じです。
受け取った辞書を書き換えても呼び出し元は変わらない
これは安全側の挙動です。**kwargs は呼び出しごとに新しい辞書として作られるので、関数の中で書き換えても呼び出し元の辞書には影響しません。
d = {'a': 1}
def mut(**kw):
kw['a'] = 999
return kw
r = mut(**d)
print(d) # {'a': 1} ← 元の辞書は変わらない
print(r) # {'a': 999}
print(d is r) # False ← 別のオブジェクト
ただし辞書の中身が可変オブジェクト(リストなど)だった場合、その中身は共有されます。浅いコピーと同じ扱いだと考えてください。
デコレータで使うときに失うもの
*args, **kwargs はデコレータの定番の書き方ですが、そのままだと元の関数の情報が消えます。実測すると分かります。
import functools, inspect
def deco_bad(fn):
def inner(*a, **kw):
return fn(*a, **kw)
return inner
def deco_ok(fn):
@functools.wraps(fn) # ← これが要る
def inner(*a, **kw):
return fn(*a, **kw)
return inner
def target(x, y=1):
"""足し算する"""
return x + y
__name__ |
__doc__ |
inspect.signature() |
|
|---|---|---|---|
functools.wraps なし |
inner |
None |
(*a, **kw) |
functools.wraps あり |
target |
'足し算する' |
(x, y=1) |
いちばん実害が大きいのはシグネチャです。wraps を付けないと、エディタの補完もヘルプも (*a, **kw) しか出さなくなります。デコレータを書くときは必ず functools.wraps を付けてください。
性能|実際に測った
「**kwargs は遅い」と言われますが、どれくらいかを測りました。Python 3.9.6・各1,000万回の実測値です。
| 書き方 | 1,000万回 | 1回あたり | 位置引数との比 |
|---|---|---|---|
direct(1, 2)(位置引数) |
0.509 秒 | 51 ns | 1.0倍 |
direct(a=1, b=2)(キーワード) |
0.556 秒 | 56 ns | 1.1倍 |
direct(**d)(辞書を展開) |
1.302 秒 | 130 ns | 2.6倍 |
kw(a=1, b=2)(**kwargs で受ける) |
0.946 秒 | 95 ns | 1.9倍 |
kw(**d)(両方) |
1.736 秒 | 174 ns | 3.4倍 |
比率で見ると3.4倍ですが、絶対値では1回174ナノ秒です。1万回呼んでも合計2ミリ秒以下です。ループの内側で毎回呼ぶような場所以外では、速度を理由に避ける必要はありません。読みやすさを優先してください。
逆に言えば、1秒間に何百万回も呼ばれる関数では効いてきます。そういう箇所だけ位置引数に書き換えるのが現実的な判断です。
使うべき場面と、避けたほうがよい場面
使うとよい場面
- 他の関数へそのまま引き渡す|ラッパーやデコレータ。引数が増えても書き換えが要らない
- ハイフンを含むキーを扱う|HTTPヘッダーなど、変数名にできない名前
- 親クラスへ引数を渡す|
super().__init__(**kwargs) - 設定値が多く、ほとんど省略される|描画オプションなど
避けたほうがよい場面
- 公開するAPIの引数|何を渡せるのかが呼び出し側から見えなくなる
- 必須の引数|書き忘れても関数の中まで進んでしまい、原因が分かりにくい
- 引数が3つ4つに決まっている|明示したほうが補完も型チェックも効く
- 受け取った値をそのまま別の処理へ流す場所|想定外のキーが混ざっても気づけない
最後の点は実務でよく問題になります。受け取るキーを決めているなら、検証を入れるだけで事故が減ります。
ALLOWED = {'color', 'size'}
def draw(**kw):
unknown = set(kw) - ALLOWED
if unknown:
raise TypeError('未知のオプション: %s(使えるのは %s)'
% (', '.join(sorted(unknown)), ', '.join(sorted(ALLOWED))))
return {k: kw.get(k) for k in ALLOWED}
draw(color='red') # {'size': None, 'color': 'red'}
draw(color='red', sise=10) # TypeError: 未知のオプション: sise(使えるのは color, size)
sise のような打ち間違いは、検証がないと黙って無視されます。色が変わらない理由を延々と探すことになるので、数行で止めておく価値があります。
型ヒントはどう書くか
**kwargs の型注釈は「値の型」を書きます。辞書全体の型ではありません。
def f(**kwargs: int) -> int:
# kwargs は dict[str, int] として扱われる
return sum(kwargs.values())
キーごとに型を変えたい場合は、Python 3.12 で入った Unpack とTypedDict の組み合わせ(PEP 692)が使えます。
# Python 3.12 以降
from typing import TypedDict, Unpack
class Opts(TypedDict):
color: str
size: int
def draw(**kwargs: Unpack[Opts]) -> None:
...
この最後の例は Python 3.9.6 では動かないため、当記事では実行検証していません。3.12より前の環境では typing_extensions から Unpack を取り込む方法があります。使う前にご自身の環境で確認してください。
よくある質問
*args と **kwargs の違いは何ですか
*args は位置引数をタプルで受け取り、**kwargs はキーワード引数を辞書で受け取ります。両方書く場合は *args が先です。
名前は kwargs でなければいけませんか
いいえ。**options でも **config でも動きます。意味が伝わる名前のほうが読みやすくなります。ただし慣習として kwargs が広く使われているので、汎用的な受け渡しでは kwargs のままが無難です。
渡されたキーの順番は保証されますか
されます。Python 3.6 以降、呼び出し時に書いた順がそのまま保たれます(PEP 468)。
**kwargs の中身が空かどうかはどう調べますか
if not kwargs: で判定できます。何も渡さずに呼んだ場合も **{} を渡した場合も、どちらも空の辞書になります。
必須の引数を **kwargs で受け取ってもよいですか
勧めません。書き忘れても呼び出しは通ってしまい、関数の中で KeyError になるまで気づけません。必須ならキーワード専用引数(def f(*, name))にすると、呼び出した瞬間に TypeError で止まります。
まとめ
**kwargsが受け取るのは辞書。渡した順番は保たれる(PEP 468)- 定義の順番は通常 → デフォルト値つき → *args → キーワード専用 → **kwargs。間違えると
SyntaxError - ハイフンを含むキーも
**で渡せる。ただし仮引数名にはできない - エラーは「for argument」と「for keyword argument」で原因が違う
- デコレータでは
functools.wrapsが必須。付けないとシグネチャが(*a, **kw)になる - 速度は位置引数の3.4倍・1回174ナノ秒。ホットループ以外では気にしなくてよい
- 受け取るキーを決めているなら検証を数行書く。打ち間違いが黙って無視される
手を動かして確かめるのがいちばん早い題材です。テックジムでは東京・永田町の東京本校でゼロからはじめるPython入門講座(無料・対面・毎週開催)を開催しています。参加費はかかりません。
あわせて読みたい
- Pythonの*args徹底解説|位置引数をまとめて受け取る書き方
- Python引数展開完全ガイド|リスト・タプル・辞書のアンパック
- functools.wraps()とは?|デコレータで関数情報を保つ方法
- inspect.signature()とは?|関数の引数を調べる方法
- Pythonデフォルト引数完全ガイド|可変デフォルト値の落とし穴
- TypedDictとは?|辞書のキーと型を定義する方法
- 引数エラーとは?|TypeErrorの原因と直し方
- Python 関数の使い方|定義・引数・戻り値の基本
掲載したコードの出力・エラーメッセージ・実行時間は、すべて Python 3.9.6 で 2026年9月28日 に実行して得たものです。Python 3.10 以降はエラーメッセージの文面が一部変わります。Python 3.12 の Unpack の例のみ、当環境では実行していません。




