Python関数の可変長キーワード引数(**kwargs):任意の数のオプション引数を受け取る方法

関数を定義する際、必須の引数とは別に、任意の数の「オプション設定」や「追加属性」を受け取りたい場合があります。

前回の記事で紹介した *args は「位置引数」をタプルとして受け取るものでしたが、引数の名前(キー)と値のセットを辞書として受け取りたい場合は、**kwargs を使用します。

この記事では、**kwargs の基本的な使い方と、*args と併用する際の重要なルールについて解説します。

目次

可変長キーワード引数 **kwargs とは

関数定義の引数名の前にアスタリスクを2つ(**)付けると、その引数は呼び出し時に渡された「残りのキーワード引数すべて」を**辞書(dict)**として受け取ります。

慣習として変数名には kwargs(keyword argumentsの略)が使われますが、**options**attributes のように任意の名前を付けることも可能です。

基本的な使い方

具体的な使用例として、ユーザーのプロファイルを作成する関数を考えます。名前とメールアドレスは必須ですが、それ以外の属性(年齢、職業、住所など)はユーザーによって異なるため、**kwargs で柔軟に受け取ります。

def create_user_profile(username, email, **attributes):
    """
    必須情報と、任意の追加属性を受け取ってプロファイルを表示する
    """
    print(f"--- User: {username} ---")
    print(f"Email: {email}")
    
    # attributes は辞書として受け取られる
    print(f"追加属性の数: {len(attributes)}")
    print(f"型: {type(attributes)}")
    
    # 辞書なので .items() でループ処理が可能
    for key, value in attributes.items():
        print(f"  {key}: {value}")

# --- 関数の呼び出し ---

# 1. 必須引数のみ
create_user_profile("Suzuki", "suzuki@example.com")

print("\n")

# 2. 必須引数 + 任意のキーワード引数
create_user_profile(
    "Tanaka", 
    "tanaka@example.com", 
    age=30, 
    job="Engineer", 
    city="Tokyo"
)

実行結果:

--- User: Suzuki ---
Email: suzuki@example.com
追加属性の数: 0
型: <class 'dict'>


--- User: Tanaka ---
Email: tanaka@example.com
追加属性の数: 3
型: <class 'dict'>
  age: 30
  job: Engineer
  city: Tokyo

age=30 などの引数は、create_user_profile 関数の内部では {'age': 30, 'job': 'Engineer', 'city': 'Tokyo'} という辞書として扱われます。

位置引数、*args**kwargs の併用

Pythonの関数では、これら3種類の引数をすべて組み合わせて定義することができます。

ただし、定義する順序には厳格なルールがあります。必ず以下の順序で記述しなければなりません。

  1. 位置引数 (通常の引数)
  2. *args (可変長位置引数)
  3. **kwargs (可変長キーワード引数)

構文:

def 関数名(位置引数, *args, **kwargs):
    # 処理

具体的な使用例

ログ出力関数を作成し、重要度(位置引数)、メッセージ内容(可変長位置引数)、メタデータ(可変長キーワード引数)を一度に受け取る例です。

def write_system_log(severity, *messages, **metadata):
    print(f"[{severity}]")
    
    # メッセージ (tuple) の処理
    for msg in messages:
        print(f"  Message: {msg}")
        
    # メタデータ (dict) の処理
    if metadata:
        print("  Metadata:")
        for key, val in metadata.items():
            print(f"    {key} = {val}")

# --- 呼び出し ---
write_system_log(
    "ERROR",                # severity (位置引数)
    "Connection failed",    # *messages (1つ目)
    "Timeout occurred",     # *messages (2つ目)
    user_id=101,            # **metadata
    timestamp="12:00:00"    # **metadata
)

実行結果:

[ERROR]
  Message: Connection failed
  Message: Timeout occurred
  Metadata:
    user_id = 101
    timestamp = 12:00:00

この順序を守らないと、SyntaxError が発生します。

辞書をアンパックして渡す

すでに辞書として持っているデータを、キーワード引数として関数に渡したい場合は、呼び出し側で ** を使って辞書をアンパック(展開)します。

# 辞書データ
user_info = {
    "age": 25,
    "job": "Designer",
    "city": "Osaka"
}

# 辞書をそのまま渡すとエラーになる(引数の数が合わない、または位置引数として扱われる)
# create_user_profile("Sato", "sato@example.com", user_info) 

# ** を付けて展開して渡す
create_user_profile("Sato", "sato@example.com", **user_info)

これは age=25, job="Designer", city="Osaka" と個別に指定したのと同じ扱いになります。

まとめ

  • 引数に ** を付ける(例: **kwargs)と、任意の数のキーワード引数を辞書として受け取れます。
  • 定義順序は重要です。def func(arg, *args, **kwargs): の順でなければなりません。
  • 呼び出し側で辞書に ** を付けると、キーワード引数として展開して関数に渡すことができます。

APIのラッパー関数や、設定オプションが多い関数を作成する際に、この機能は非常に強力なツールとなります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次