メインコンテンツへスキップ
Lesson5 / 8

可変長引数(*args, **kwargs)

目次

1. このレッスンで学ぶこと

  • 可変長引数とは何か
  • *argsの使い方
  • **kwargsの使い方
  • 実践的な活用方法

2. 可変長引数とは

可変長引数は、任意の数の引数を受け取れる特別な引数です。

構成要素

要素説明
*args可変長位置引数def func(*args)
**kwargs可変長キーワード引数def func(**kwargs)
タプルargsの型(1, 2, 3)
辞書kwargsの型{'a': 1, 'b': 2}

主な特徴

  • 引数の数を固定しなくてよい
  • *argsは位置引数をタプルで受け取る
  • **kwargsはキーワード引数を辞書で受け取る
  • 柔軟な関数を作成できる

シンプルな例

Python
# *argsで任意の数の引数を受け取る
def add_all(*numbers):
    total = sum(numbers)
    return total

# 様々な数の引数で呼び出し
print(f"合計: {add_all(1, 2, 3)}")
print(f"合計: {add_all(10, 20, 30, 40, 50)}")

実行結果:

合計: 6
合計: 150

3. なぜ可変長引数が必要か?

引数の数が決まっていない関数を作りたい場合があります。

Python
# 2つの数値しか足せない
def add_two(a, b):
    return a + b

# 何個でも足せる
def add_all(*numbers):
    return sum(numbers)

result = add_all(1, 2, 3, 4, 5)
print(result)  # 15

可変長引数を使うことで、柔軟な関数を作れます。

💡 豆知識: *argsの「args」は「arguments」の略で、**kwargsの「kwargs」は「keyword arguments」の略です。これらは慣習的な名前で、実際には*values**optionsなど別の名前も使えますが、Pythonコミュニティでは*args**kwargsを使うのが一般的です。


4. *args(可変長位置引数)

基本的な使い方

機能: 任意の数の位置引数を受け取ります。

書き方:

Python
def 関数名(*args):
    # argsはタプル
    処理

用途: 引数の数が不定の関数

注意点: argsはタプルとして扱う

Python
# 任意の数の引数を受け取る
def print_all(*args):
    print(f"受け取った引数の数: {len(args)}")
    print(f"型: {type(args)}")
    for i, arg in enumerate(args, 1):
        print(f"  {i}: {arg}")

# 様々な数の引数で呼び出し
print_all(1)
print()

print_all(1, 2, 3)
print()

print_all("apple", "banana", "orange", "grape")

実行結果:

受け取った引数の数: 1
型: <class 'tuple'>
  1: 1

受け取った引数の数: 3
型: <class 'tuple'>
  1: 1
  2: 2
  3: 3

受け取った引数の数: 4
型: <class 'tuple'>
  1: apple
  2: banana
  3: orange
  4: grape

*argsの実用例

Python
# 合計を計算
def calculate_sum(*numbers):
    total = sum(numbers)
    return total

print(f"合計: {calculate_sum(1, 2, 3, 4, 5)}")
print(f"合計: {calculate_sum(10, 20)}")

# 平均を計算
def calculate_average(*numbers):
    if not numbers:
        return 0
    return sum(numbers) / len(numbers)

print(f"\n平均: {calculate_average(85, 92, 78, 95, 88):.2f}")

# 最大値と最小値
def get_min_max(*numbers):
    if not numbers:
        return None, None
    return min(numbers), max(numbers)

min_val, max_val = get_min_max(5, 2, 8, 1, 9, 3)
print(f"\n最小: {min_val}, 最大: {max_val}")

実行結果:

合計: 15
合計: 30

平均: 87.60

最小: 1, 最大: 9

通常の引数と*argsの組み合わせ

Python
# 最初の引数は必須、残りは可変
def greet(greeting, *names):
    for name in names:
        print(f"{greeting}{name}さん")

greet("こんにちは", "太郎")
print()

greet("おはよう", "花子", "次郎", "三郎")
print()

# 必須引数とオプション引数
def create_message(title, *contents, separator="\n"):
    message = f"【{title}】\n"
    message += separator.join(contents)
    return message

msg1 = create_message("お知らせ", "明日は休みです", "よろしくお願いします")
print(msg1)

print()

msg2 = create_message("重要", "会議があります", "資料を準備してください",
                     "時間厳守", separator=" / ")
print(msg2)

実行結果:

こんにちは、太郎さん

おはよう、花子さん
おはよう、次郎さん
おはよう、三郎さん

【お知らせ】
明日は休みです
よろしくお願いします

【重要】
会議があります / 資料を準備してください / 時間厳守

5. **kwargs(可変長キーワード引数)

基本的な使い方

機能: 任意の数のキーワード引数を受け取ります。

書き方:

Python
def 関数名(**kwargs):
    # kwargsは辞書
    処理

用途: キーワード引数の数が不定の関数

注意点: kwargsは辞書として扱う

Python
# 任意の数のキーワード引数を受け取る
def print_info(**kwargs):
    print(f"受け取った引数の数: {len(kwargs)}")
    print(f"型: {type(kwargs)}")
    for key, value in kwargs.items():
        print(f"  {key}: {value}")

# 様々なキーワード引数で呼び出し
print_info(name="太郎")
print()

print_info(name="花子", age=25, city="東京")
print()

print_info(product="ノートPC", price=98000, stock=5, category="電子機器")

実行結果:

受け取った引数の数: 1
型: <class 'dict'>
  name: 太郎

受け取った引数の数: 3
型: <class 'dict'>
  name: 花子
  age: 25
  city: 東京

受け取った引数の数: 4
型: <class 'dict'>
  product: ノートPC
  price: 98000
  stock: 5
  category: 電子機器

**kwargsの実用例

Python
# ユーザー情報を作成
def create_user(user_id, **info):
    user = {"id": user_id}
    user.update(info)
    return user

user1 = create_user(1001, name="太郎", email="taro@example.com")
print(f"ユーザー1: {user1}")

user2 = create_user(1002, name="花子", age=25, city="東京", premium=True)
print(f"ユーザー2: {user2}")

# 設定を作成
def build_config(**settings):
    default = {
        "debug": False,
        "timeout": 30,
        "retries": 3
    }
    default.update(settings)
    return default

config1 = build_config()
print(f"\nデフォルト設定: {config1}")

config2 = build_config(debug=True, timeout=60)
print(f"カスタム設定: {config2}")

実行結果:

ユーザー1: {'id': 1001, 'name': '太郎', 'email': 'taro@example.com'}
ユーザー2: {'id': 1002, 'name': '花子', 'age': 25, 'city': '東京', 'premium': True}

デフォルト設定: {'debug': False, 'timeout': 30, 'retries': 3}
カスタム設定: {'debug': True, 'timeout': 60, 'retries': 3}

6. *argsと**kwargsの組み合わせ

全ての引数パターンを受け取る

Python
def flexible_function(required, *args, option1=None, **kwargs):
    """全パターンの引数を受け取る"""
    print(f"必須引数: {required}")
    print(f"可変位置引数: {args}")
    print(f"オプション1: {option1}")
    print(f"可変キーワード引数: {kwargs}")

# 様々な呼び出し方
flexible_function("必須値")
print()

flexible_function("必須値", "追加1", "追加2")
print()

flexible_function("必須値", "追加1", option1="オプション値")
print()

flexible_function("必須値", "追加1", "追加2",
                 option1="オプション値",
                 extra1="その他1", extra2="その他2")

実行結果:

必須引数: 必須値
可変位置引数: ()
オプション1: None
可変キーワード引数: {}

必須引数: 必須値
可変位置引数: ('追加1', '追加2')
オプション1: None
可変キーワード引数: {}

必須引数: 必須値
可変位置引数: ('追加1',)
オプション1: オプション値
可変キーワード引数: {}

必須引数: 必須値
可変位置引数: ('追加1', '追加2')
オプション1: オプション値
可変キーワード引数: {'extra1': 'その他1', 'extra2': 'その他2'}

7. 引数の展開

リストやタプルの展開(*)

Python
def add_three(a, b, c):
    return a + b + c

# 通常の呼び出し
result1 = add_three(1, 2, 3)
print(f"通常: {result1}")

# リストを展開して渡す
numbers = [10, 20, 30]
result2 = add_three(*numbers)
print(f"リスト展開: {result2}")

# タプルを展開して渡す
values = (5, 10, 15)
result3 = add_three(*values)
print(f"タプル展開: {result3}")

実行結果:

通常: 6
リスト展開: 60
タプル展開: 30

辞書の展開(**)

Python
def show_person(name, age, city):
    print(f"名前: {name}")
    print(f"年齢: {age}歳")
    print(f"都市: {city}")

# 通常の呼び出し
show_person("太郎", 25, "東京")
print()

# 辞書を展開して渡す
person = {
    "name": "花子",
    "age": 30,
    "city": "大阪"
}
show_person(**person)

実行結果:

名前: 太郎
年齢: 25歳
都市: 東京

名前: 花子
年齢: 30歳
都市: 大阪

8. 具体例

例1: ロガー関数

Python
def log(level, message, **details):
    """ログを出力"""
    print(f"[{level}] {message}")

    if details:
        print("  詳細情報:")
        for key, value in details.items():
            print(f"    {key}: {value}")

# シンプルなログ
log("INFO", "処理を開始しました")
print()

# 詳細情報付きログ
log("WARNING", "接続エラーが発生しました",
    host="localhost", port=8000, retry_count=3)
print()

log("ERROR", "データベースエラー",
    error_code=500, table="users", query="SELECT * FROM users")

実行結果:

[INFO] 処理を開始しました

[WARNING] 接続エラーが発生しました
  詳細情報:
    host: localhost
    port: 8000
    retry_count: 3

[ERROR] データベースエラー
  詳細情報:
    error_code: 500
    table: users
    query: SELECT * FROM users

例2: SQLクエリビルダー

Python
def build_select_query(table, *columns, **conditions):
    """SELECTクエリを構築"""
    # カラム指定
    if columns:
        cols = ", ".join(columns)
    else:
        cols = "*"

    # WHERE句
    where_clauses = []
    for key, value in conditions.items():
        if isinstance(value, str):
            where_clauses.append(f"{key}='{value}'")
        else:
            where_clauses.append(f"{key}={value}")

    where = " AND ".join(where_clauses) if where_clauses else "1=1"

    query = f"SELECT {cols} FROM {table} WHERE {where}"
    return query

# 全カラム取得
query1 = build_select_query("users")
print(query1)

# 特定カラム取得
query2 = build_select_query("users", "id", "name", "email")
print(query2)

# 条件付き
query3 = build_select_query("users", "name", "age", city="東京", active=1)
print(query3)

# 複雑な条件
query4 = build_select_query("products", "name", "price",
                           category="電子機器", stock=10, price=50000)
print(query4)

実行結果:

SELECT * FROM users WHERE 1=1
SELECT id, name, email FROM users WHERE 1=1
SELECT name, age FROM users WHERE city='東京' AND active=1
SELECT name, price FROM products WHERE category='電子機器' AND stock=10 AND price=50000

例3: デコレータ風の関数

Python
def measure_performance(func, *args, **kwargs):
    """関数の実行時間を測定"""
    import time

    start = time.time()
    result = func(*args, **kwargs)
    end = time.time()

    print(f"関数 {func.__name__} の実行時間: {end - start:.4f}秒")
    return result

# テスト用の関数
def calculate_sum(*numbers):
    return sum(numbers)

def process_data(data, multiplier=1):
    return [x * multiplier for x in data]

# 実行時間を測定
result1 = measure_performance(calculate_sum, 1, 2, 3, 4, 5)
print(f"合計: {result1}\n")

result2 = measure_performance(process_data, [1, 2, 3, 4, 5], multiplier=10)
print(f"処理結果: {result2}")

実行結果:

関数 calculate_sum の実行時間: 0.0000秒
合計: 15

関数 process_data の実行時間: 0.0000秒
処理結果: [10, 20, 30, 40, 50]

9. 練習問題

問題1(基礎)⭐☆☆

可変長引数 *args を受け取り、すべての引数の合計を計算して返す関数 sum_all を作成してください。以下の呼び出しで動作を確認してください:

  • sum_all(1, 2, 3)
  • sum_all(10, 20, 30, 40, 50)
💡 ヒント
  1. def sum_all(*args): で関数を定義
  2. args はタプルなので、sum() 関数で合計を計算できる
  3. return sum(args) で結果を返す
  4. または for ループで合計を計算してもOK
✅ 解答例
Python
def sum_all(*args):
    # argsはタプルなのでsum()で合計を計算
    return sum(args)

# 3つの引数
result1 = sum_all(1, 2, 3)
print(f"1 + 2 + 3 = {result1}")

# 5つの引数
result2 = sum_all(10, 20, 30, 40, 50)
print(f"10 + 20 + 30 + 40 + 50 = {result2}")

# 1つの引数
result3 = sum_all(100)
print(f"100 = {result3}")

実行結果:

1 + 2 + 3 = 6
10 + 20 + 30 + 40 + 50 = 150
100 = 100

解説: *args を使うことで、任意の個数の引数を受け取れます。args は受け取った引数をタプルとして保持するため、sum(args) で簡単に合計を計算できます。引数の個数に制限がないため、1個でも10個でも対応できます。


問題2(基礎)⭐☆☆

可変長キーワード引数 **kwargs を受け取り、すべてのキーと値を「キー: 値」の形式で表示する関数 show_info を作成してください。以下の呼び出しで動作を確認してください:

  • show_info(name="太郎", age=25, city="東京")
💡 ヒント
  1. def show_info(**kwargs): で関数を定義
  2. kwargs は辞書なので、.items() でキーと値のペアを取得
  3. for key, value in kwargs.items(): でループ
  4. f-stringを使って「キー: 値」形式で表示
✅ 解答例
Python
def show_info(**kwargs):
    print("=== 情報 ===")
    for key, value in kwargs.items():
        print(f"{key}: {value}")

# キーワード引数で呼び出し
show_info(name="太郎", age=25, city="東京")
print()

# 別のパターン
show_info(product="ノートPC", price=98000, stock=5, brand="ExampleBrand")

実行結果:

=== 情報 ===
name: 太郎
age: 25
city: 東京

=== 情報 ===
product: ノートPC
price: 98000
stock: 5
brand: ExampleBrand

解説: **kwargs を使うことで、任意の個数のキーワード引数を受け取れます。kwargs は辞書として扱えるため、.items() メソッドでキーと値のペアを取得し、ループで順番に表示できます。キーワード引数の名前や個数を事前に知らなくても、柔軟に対応できます。


問題3(応用)⭐⭐☆

名前を必須引数、教科名と点数を可変長キーワード引数 **scores として受け取る関数 calculate_average を作成してください。この関数は、各教科の点数の平均を計算して、以下の形式で表示します:

名前: 〇〇
教科1: △△点
教科2: □□点
平均点: ××.×点

以下の呼び出しで動作を確認してください:

  • calculate_average("太郎", math=85, english=92, science=78)
💡 ヒント
  1. def calculate_average(name, **scores): で関数を定義
  2. scores.items() でキーと値のペアを取得
  3. scores.values() で点数だけを取得
  4. sum(scores.values()) / len(scores) で平均を計算
  5. f-stringを使って整形して表示
✅ 解答例
Python
def calculate_average(name, **scores):
    print(f"名前: {name}")

    # 各教科の点数を表示
    for subject, score in scores.items():
        print(f"{subject}: {score}点")

    # 平均点を計算
    if scores:
        average = sum(scores.values()) / len(scores)
        print(f"平均点: {average:.1f}点")
    else:
        print("教科データがありません")

# 3教科の場合
calculate_average("太郎", math=85, english=92, science=78)
print()

# 5教科の場合
calculate_average("花子", math=90, english=88, science=85, social=92, japanese=87)
print()

# 2教科の場合
calculate_average("次郎", math=70, english=75)

実行結果:

名前: 太郎
math: 85点
english: 92点
science: 78点
平均点: 85.0点

名前: 花子
math: 90点
english: 88点
science: 85点
social: 92点
japanese: 87点
平均点: 88.4点

名前: 次郎
math: 70点
english: 75点
平均点: 72.5点

解説: 必須引数 name と可変長キーワード引数 **scores を組み合わせることで、教科数に関係なく柔軟に成績を受け取れます。scores.items() で各教科と点数のペアを表示し、scores.values() で点数だけを取り出して平均を計算します。この方法を使えば、3教科でも5教科でも同じ関数で対応できます。


10. まとめ

このレッスンでは、可変長引数で柔軟な関数を作る方法を学びました。

  • *args**kwargs で可変入力を受け取れることを理解しました。
  • 引数数が未定の関数でも、共通処理を実装できます。
  • 位置引数・キーワード引数との組み合わせルールを確認しました。
  • 受け取った引数をループや辞書処理で活用する方法を実践しました。
  • 柔軟性と可読性のバランスを意識した関数設計が重要です。