Pythonの**kwargs(キーワード引数)について

**kwargsは、Pythonの関数定義で使われる非常に便利な機能です。関数に任意の数のキーワード引数(名前付き引数)を渡すために使用されます。kwargsは「キーワード引数」を意味し、**はそれらを辞書として展開するという意味です。

**kwargsの基本的な使い方

関数に**kwargsを使用すると、任意のキーワード引数を受け取ることができます。これらの引数は辞書形式で関数内に渡されます。

例1:**kwargsを使った関数の定義

def my_function(**kwargs):
    print(kwargs)

my_function(name="John", age=25, city="New York")

この場合、出力は次のようになります。

{'name': 'John', 'age': 25, 'city': 'New York'}

ここで、kwargsは関数に渡されたキーワード引数を含む辞書になっています。

解説

**kwargsは複数のキーワード引数を辞書として受け取ることができます。関数呼び出し時に、何個でも引数を渡すことができ、それらが辞書として渡されます。
関数内でkwargsを辞書として扱うことで、特定のキーにアクセスしたり、以下のようにループで全てのキーと値を処理したりできます。

例2:**kwargsで引数を処理する

def my_function(**kwargs):
    for key, value in kwargs.items():
        print(f"{key} = {value}")

my_function(name="Alice", age=30, job="Engineer")

出力

name = Alice
age = 30
job = Engineer

**kwargsの用途

  1. オプションの引数を受け取る場合
    関数に必須ではない複数の引数を渡したい場合に便利です。ユーザーが任意の数の引数を渡すことができ、その引数を辞書形式で処理できます。
  2. 動的な引数の処理
    引数の数や名前が事前にわからない状況で、関数が柔軟に引数を処理できるようにします。

可変長引数(*args)との違い

*argsは位置引数(非キーワード引数)をタプルとして受け取るのに対し、**kwargsはキーワード引数を辞書として受け取ります。*argsは複数の引数を、**kwargsは複数のキーワード引数を扱うために使用されます。

例3:*argと**kwargsを組み合わせた関数

def my_function(*args, **kwargs):
    print("args:", args)
    print("kwargs:", kwargs)

my_function(1, 2, 3, name="Bob", age=40)

出力

args: (1, 2, 3)
kwargs: {'name': 'Bob', 'age': 40}

辞書を利用したパラメータの設定

**kwargsを使用することで、デフォルト値を持つ引数を定義した関数に辞書形式でパラメータを渡すことができます。この方法は、必須でない引数が複数存在する場合に非常に便利です。
以下の例では、辞書に格納された値を**kwargsを使用して関数に渡すことで、必要な引数のみを指定しています。

def my_function(name="Alice", city="Tokyo", age=3):
    print(name, city, age)

src_dict = { "name": "Taro", "age": 9 }
my_function(**src_dict)

出力

Taro Tokyo 9

必須の変数名に該当するものが辞書にない場合はエラーとなります。

def my_function(name, city="Tokyo", age=3):
    print(name, city, age)

src_dict = { "name": "Taro", "age": 9 }
my_function(**src_dict)

src_dict2 = { "city": "New York", "age": 9 }
my_function(**src_dict2)

出力

Taro Tokyo 9
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    my_function(**src_dict2)
TypeError: my_function() missing 1 required positional argument: 'name'

必須でない引数だけを**kwargsで渡すこともできます。

def my_function(name, city="Tokyo", age=3):
    print(name, city, age)

src_dict = { "age": 9 }
my_function("Taro", **src_dict)

出力

Taro Tokyo 9

個人的には関数側で受け取る引数を明示的に記載し、辞書を使用してパラメータを渡すこちらのほうが、関数がどのような引数を受け取るのかが明確になり、可読性が向上するため好ましいと考えています。

Pydanticにおける**kwargsを使用した代入

以下のように、Pydanticモデルへ**kwargsを使ってデータを代入できます。この手法は、特に外部データソースからのデータを受け取る場合に便利です。

from pydantic import BaseModel
from typing import Union

class User(BaseModel):
    username: str
    password: Union[str, None] = None
#;

src_dict = { "username": "Taro", "password": "secret" }
user = User(**src_dict)

上記のuser = User(**src_dict)は次のコードと同じになります。

User(
    username = dict["username"],
    password = dict["password"]
)

実行例

from pydantic import BaseModel
from typing import Union

class User(BaseModel):
    username: str
    password: Union[str, None] = None
#;

src_dict = { "username": "Taro", "password": "secret" }
user = User(**src_dict)
print(user)

src_dict = { "username": "Taro" }
user = User(**src_dict)
print(user)

# Userのフィールドにないキーは無視される
src_dict = { "username": "Taro", "password": "secret", "ext": -1 }
user = User(**src_dict)
print(user)
username='Taro' password='secret'
username='Taro' password=None
username='Taro' password='secret'

なお、必須のフィールドに該当するキーが辞書に存在しない場合、エラーが発生します。

from pydantic import BaseModel
from typing import Union

class User(BaseModel):
    username: str
    password: Union[str, None] = None
#;

src_dict = { "password": "secret" }
user = User(**src_dict) # pydantic.error_wrappers.ValidationError

**kwargsのまとめ

  • **kwargsは、関数に任意の数のキーワード引数を渡すための機能で、これらの引数は辞書として関数内でアクセスできる
  • 柔軟性が高く、複数のオプション引数を扱う場合や、引数の名前や数が動的に変わる場面で役立つ
このエントリーをはてなブックマークに追加
にほんブログ村 IT技術ブログへ

コメント

メールアドレスが公開されることはありません。 が付いている欄は必須項目です