関数を定義する際、引数の数が事前に決まっていない場合があります。例えば、渡された複数の数値をすべて合計する関数や、複数のログメッセージをまとめて出力する関数などです。
Pythonでは、引数名の前にアスタリスク(*)を付けることで、任意の数(0個以上)の引数をまとめて受け取ることができます。これを「可変長位置引数」と呼びます。
この記事では、*args の基本的な使い方と、通常の引数と組み合わせる際のルールについて解説します。
可変長位置引数 *args とは
関数定義の引数に * を付けると、その引数は呼び出し時に渡された「残りの位置引数すべて」を**タプル(tuple)**として受け取ります。
慣習として変数名には args(argumentsの略)が使われますが、*items や *values のように好きな名前を付けることも可能です。重要なのは先頭の * です。
基本的な使い方
具体的な使用例として、サーバー名と、そこに記録したい複数のイベントメッセージを受け取る関数を作成します。メッセージの数は呼び出しごとに異なる可能性があります。
def print_server_log(server_name, *messages):
"""
サーバー名と、任意の数のメッセージを受け取って表示する関数
"""
print(f"--- Server: {server_name} ---")
# messages はタプルとして受け取られる
print(f"受信したメッセージ数: {len(messages)}")
print(f"型: {type(messages)}")
if not messages:
print(" (メッセージはありません)")
else:
for msg in messages:
print(f" - {msg}")
# --- 関数の呼び出し ---
# 1. 必須引数のみ、可変長引数はなし
print_server_log("Web-Server-01")
print("\n")
# 2. 必須引数 + 複数のメッセージ
print_server_log("DB-Server-01", "接続を開始", "クエリ実行", "切断完了")
実行結果:
--- Server: Web-Server-01 ---
受信したメッセージ数: 0
型: <class 'tuple'>
(メッセージはありません)
--- Server: DB-Server-01 ---
受信したメッセージ数: 3
型: <class 'tuple'>
- 接続を開始
- クエリ実行
- 切断完了
*messages は、渡された引数(”接続を開始”, “クエリ実行”, “切断完了”)を要素に持つタプル ('接続を開始', 'クエリ実行', '切断完了') となります。引数が渡されなかった場合は空のタプル () になります。
引数の順序に関するルール
可変長位置引数を使用する場合、引数を定義する順序には厳格なルールがあります。
*args は、通常の位置引数(必須引数)よりも後ろに記述する必要があります。
Pythonは引数を先頭から順番に割り当てていき、対応する変数がない残りの部分を *args に格納するためです。
正しい定義順序
# OK: 必須引数が先、可変長引数が後
def calculate_total(tax_rate, *prices):
total = sum(prices)
return int(total * (1 + tax_rate))
# 税率 0.1 (10%) で、100, 200, 300 の合計を計算
print(calculate_total(0.1, 100, 200, 300))
誤った定義順序
# NG: 可変長引数が先に来ると、tax_rate に値を渡す手段がなくなる
# (すべての引数が *prices に吸い込まれてしまうため)
# def calculate_wrong(*prices, tax_rate):
# pass
もし *args の後ろに引数を定義した場合、それらは「キーワード専用引数」となり、呼び出し時に必ず 引数名=値 の形式で指定しなければならなくなります。
リストやタプルを展開して渡す
すでにリストやタプルとして持っているデータを、可変長引数を持つ関数に渡したい場合は、呼び出し側でも * を使ってデータをアンパック(展開)します。
log_data = ["エラー発生", "再起動を実行", "復旧"]
# リストをそのまま渡すと、タプルの要素が「リスト1個」になってしまう
# print_server_log("App-Server", log_data)
# -> messages = (['エラー発生', '再起動を実行', '復旧'],)
# * を付けて展開して渡す
print_server_log("App-Server", *log_data)
# -> messages = ('エラー発生', '再起動を実行', '復旧')
まとめ
- 引数に
*を付ける(例:*args)と、任意の数の位置引数をタプルとして受け取れます。 *argsは通常の位置引数よりも後ろに定義します。- 呼び出し側でリストに
*を付けると、要素を展開して関数に渡すことができます。
