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 3.9.6 で 2026年9月28日 に実行して得たものです。Python 3.10 以降はエラーメッセージの文面が一部変わります。Python 3.12 の Unpack の例のみ、当環境では実行していません。