関数を定義する際、必須の引数とは別に、任意の数の「オプション設定」や「追加属性」を受け取りたい場合があります。
前回の記事で紹介した *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種類の引数をすべて組み合わせて定義することができます。
ただし、定義する順序には厳格なルールがあります。必ず以下の順序で記述しなければなりません。
- 位置引数 (通常の引数)
*args(可変長位置引数)**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のラッパー関数や、設定オプションが多い関数を作成する際に、この機能は非常に強力なツールとなります。
