Python引数展開完全ガイド【リスト・タプル・辞書のアンパック】初心者向け
Pythonプログラミングにおいて、リスト、タプル、辞書を関数の引数として展開(アンパック)する機能は非常に便利です。この記事では、*(アスタリスク)と**(ダブルアスタリスク)を使った引数展開について、基本から応用まで分かりやすく解説します。
引数展開(アンパック)とは?
引数展開とは、リスト、タプル、辞書などのコレクション型データを個別の引数として関数に渡す機能です。Pythonでは以下の記号を使用します:
*(アスタリスク):リストやタプルを位置引数として展開**(ダブルアスタリスク):辞書をキーワード引数として展開
リスト・タプルの展開(*演算子)
基本的なリスト展開
def add_three_numbers(a, b, c):
return a + b + c
numbers = [1, 2, 3]
result = add_three_numbers(*numbers) # *でリストを展開
print(result)
出力:
6
タプルの展開
def greet(first_name, last_name):
print(f"こんにちは、{first_name} {last_name}さん!")
name_tuple = ("太郎", "田中")
greet(*name_tuple) # タプルを展開
出力:
こんにちは、太郎 田中さん!
より多くの引数を持つ例
def show_info(name, age, city, job):
print(f"名前: {name}, 年齢: {age}, 出身: {city}, 職業: {job}")
person_data = ["佐藤", 30, "東京", "エンジニア"]
show_info(*person_data)
出力:
名前: 佐藤, 年齢: 30, 出身: 東京, 職業: エンジニア
辞書の展開(**演算子)
基本的な辞書展開
def create_profile(name, age, city):
return f"{name}({age}歳) - {city}出身"
person_dict = {"name": "山田", "age": 25, "city": "大阪"}
profile = create_profile(**person_dict) # **で辞書を展開
print(profile)
出力:
山田(25歳) - 大阪出身
より複雑な辞書展開
def send_email(to, subject, body, from_email="noreply@example.com"):
print(f"送信先: {to}")
print(f"件名: {subject}")
print(f"本文: {body}")
print(f"送信者: {from_email}")
email_config = {
"to": "user@example.com",
"subject": "重要なお知らせ",
"body": "会議の時間が変更になりました。",
"from_email": "admin@company.com"
}
send_email(**email_config)
出力:
送信先: user@example.com
件名: 重要なお知らせ
本文: 会議の時間が変更になりました。
送信者: admin@company.com
*と**の組み合わせ
位置引数とキーワード引数の同時展開
def complex_function(a, b, c, name="匿名", active=True):
print(f"位置引数: {a}, {b}, {c}")
print(f"名前: {name}, アクティブ: {active}")
args = [1, 2, 3]
kwargs = {"name": "鈴木", "active": False}
complex_function(*args, **kwargs)
出力:
位置引数: 1, 2, 3
名前: 鈴木, アクティブ: False
部分的な展開
def register_user(username, email, age=None, country="日本"):
print(f"ユーザー: {username}")
print(f"メール: {email}")
print(f"年齢: {age}")
print(f"国: {country}")
# 一部は直接指定、一部は辞書から展開
user_info = {"age": 28, "country": "アメリカ"}
register_user("johndoe", "john@example.com", **user_info)
出力:
ユーザー: johndoe
メール: john@example.com
年齢: 28
国: アメリカ
実践的な活用例
データベース接続設定
def connect_database(host, port, database, username, password, ssl=False):
print(f"接続先: {username}@{host}:{port}/{database}")
print(f"SSL: {'有効' if ssl else '無効'}")
return {"status": "connected"}
# 設定を辞書で管理
db_config = {
"host": "localhost",
"port": 5432,
"database": "myapp",
"username": "admin",
"password": "secret123",
"ssl": True
}
connection = connect_database(**db_config)
出力:
接続先: admin@localhost:5432/myapp
SSL: 有効
APIリクエスト関数
def make_api_request(endpoint, method="GET", headers=None, params=None):
print(f"{method} {endpoint}")
if headers:
print(f"ヘッダー: {headers}")
if params:
print(f"パラメータ: {params}")
# リクエスト設定を辞書で管理
request_config = {
"endpoint": "/api/users",
"method": "POST",
"headers": {"Content-Type": "application/json"},
"params": {"limit": 10, "offset": 0}
}
make_api_request(**request_config)
出力:
POST /api/users
ヘッダー: {'Content-Type': 'application/json'}
パラメータ: {'limit': 10, 'offset': 0}
座標計算関数
import math
def calculate_distance(x1, y1, x2, y2):
return math.sqrt((x2 - x1)**2 + (y2 - y1)**2)
# 座標をタプルで管理
point1 = (0, 0)
point2 = (3, 4)
distance = calculate_distance(*point1, *point2)
print(f"距離: {distance}")
出力:
距離: 5.0
関数定義での可変長引数との組み合わせ
*argsを受け取る関数での展開
def sum_all(*numbers):
return sum(numbers)
# リストを展開して渡す
number_list = [1, 2, 3, 4, 5]
total = sum_all(*number_list)
print(f"合計: {total}")
# 複数のリストを展開
list1 = [1, 2]
list2 = [3, 4]
total2 = sum_all(*list1, *list2, 5, 6)
print(f"合計2: {total2}")
出力:
合計: 15
合計2: 21
**kwargsを受け取る関数での展開
def log_event(**event_data):
print("イベントログ:")
for key, value in event_data.items():
print(f" {key}: {value}")
# 複数の辞書を展開
base_info = {"timestamp": "2024-01-01", "level": "INFO"}
event_info = {"action": "login", "user_id": 123}
log_event(**base_info, **event_info)
出力:
イベントログ:
timestamp: 2024-01-01
level: INFO
action: login
user_id: 123
ネストしたデータ構造の展開
2次元配列の展開
def print_matrix(row1, row2, row3):
print("行列:")
for i, row in enumerate([row1, row2, row3], 1):
print(f" 行{i}: {row}")
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print_matrix(*matrix)
出力:
行列:
行1: [1, 2, 3]
行2: [4, 5, 6]
行3: [7, 8, 9]
複雑なデータ構造の処理
def process_order(customer_name, items, shipping_info, payment_info):
print(f"顧客: {customer_name}")
print(f"商品数: {len(items)}")
print(f"配送先: {shipping_info['address']}")
print(f"支払い方法: {payment_info['method']}")
order_data = {
"customer_name": "田中太郎",
"items": ["商品A", "商品B"],
"shipping_info": {"address": "東京都渋谷区", "date": "2024-01-15"},
"payment_info": {"method": "クレジットカード", "amount": 5000}
}
process_order(**order_data)
出力:
顧客: 田中太郎
商品数: 2
配送先: 東京都渋谷区
支払い方法: クレジットカード
クラスメソッドでの引数展開
インスタンス作成での活用
class Person:
def __init__(self, name, age, email, city="東京"):
self.name = name
self.age = age
self.email = email
self.city = city
def display(self):
print(f"{self.name}({self.age}歳) - {self.email} ({self.city})")
# 辞書からインスタンス作成
person_data = {
"name": "山田花子",
"age": 28,
"email": "yamada@example.com",
"city": "大阪"
}
person = Person(**person_data)
person.display()
出力:
山田花子(28歳) - yamada@example.com (大阪)
クラスメソッドでの設定管理
class DatabaseConfig:
def __init__(self, **config):
self.host = config.get("host", "localhost")
self.port = config.get("port", 5432)
self.database = config.get("database", "default")
self.ssl = config.get("ssl", False)
def show_config(self):
print(f"DB設定: {self.host}:{self.port}/{self.database} (SSL: {self.ssl})")
config_dict = {"host": "db.example.com", "port": 3306, "ssl": True}
db_config = DatabaseConfig(**config_dict)
db_config.show_config()
出力:
DB設定: db.example.com:3306/default (SSL: True)
エラーハンドリングと展開
引数数の不一致
def requires_three_args(a, b, c):
return a + b + c
# 正常なケース
correct_list = [1, 2, 3]
print(requires_three_args(*correct_list))
# エラーケースの処理
def safe_function_call(func, args_list):
try:
return func(*args_list)
except TypeError as e:
return f"エラー: {e}"
wrong_list = [1, 2] # 引数が不足
result = safe_function_call(requires_three_args, wrong_list)
print(result)
出力:
6
エラー: requires_three_args() missing 1 required positional argument: 'c'
辞書キーの不一致
def create_user(username, email, age):
return f"ユーザー: {username} ({email}, {age}歳)"
def safe_dict_expansion(func, data_dict):
try:
return func(**data_dict)
except TypeError as e:
return f"キーエラー: {e}"
# 正常なデータ
good_data = {"username": "user1", "email": "user1@example.com", "age": 25}
print(create_user(**good_data))
# 不正なキー
bad_data = {"username": "user2", "invalid_key": "value", "age": 30}
result = safe_dict_expansion(create_user, bad_data)
print(result)
出力:
ユーザー: user1 (user1@example.com, 25歳)
キーエラー: create_user() missing 1 required positional argument: 'email'
動的関数呼び出し
関数名と引数を動的に決定
def add(a, b):
return a + b
def multiply(a, b):
return a * b
def subtract(a, b):
return a - b
# 関数と引数の組み合わせ
operations = [
(add, [10, 5]),
(multiply, [3, 4]),
(subtract, [20, 8])
]
for func, args in operations:
result = func(*args)
print(f"{func.__name__}({', '.join(map(str, args))}) = {result}")
出力:
add(10, 5) = 15
multiply(3, 4) = 12
subtract(20, 8) = 12
設定ベースの関数実行
def process_data(data, operation="sort", reverse=False, key=None):
if operation == "sort":
return sorted(data, reverse=reverse, key=key)
elif operation == "filter":
return [x for x in data if x > 0]
return data
# 設定を辞書で管理
processing_configs = [
{"operation": "sort", "reverse": True},
{"operation": "sort", "key": len},
{"operation": "filter"}
]
data = ["apple", "banana", "cherry", "date"]
for config in processing_configs:
result = process_data(data, **config)
print(f"設定 {config}: {result}")
出力:
設定 {'operation': 'sort', 'reverse': True}: ['date', 'cherry', 'banana', 'apple']
設定 {'operation': 'sort', 'key': <built-in function len>}: ['date', 'apple', 'banana', 'cherry']
設定 {'operation': 'filter'}: ['apple', 'banana', 'cherry', 'date']
よくあるエラーと対処法
1. 引数の重複
def greet(name, age):
print(f"こんにちは、{name}さん({age}歳)")
# エラー: 同じ引数を複数回指定
# greet("田中", name="佐藤", age=30) # TypeError
# 正しい方法
greet("田中", age=30)
2. 存在しないキーワード引数
def simple_func(a, b):
return a + b
# エラー: 存在しないキーワード引数
data = {"a": 1, "b": 2, "c": 3}
# simple_func(**data) # TypeError: unexpected keyword argument 'c'
# 正しい方法:必要なキーのみ抽出
filtered_data = {k: v for k, v in data.items() if k in ["a", "b"]}
result = simple_func(**filtered_data)
print(result)
出力:
3
引数展開のベストプラクティス
1. 設定管理での活用
# 設定ファイルやDBから読み込んだ設定を関数に渡す
def setup_logging(**config):
level = config.get("level", "INFO")
format_str = config.get("format", "%(message)s")
filename = config.get("filename")
print(f"ログ設定: レベル={level}, 形式={format_str}")
if filename:
print(f"ファイル出力: {filename}")
logging_config = {
"level": "DEBUG",
"format": "%(asctime)s - %(message)s",
"filename": "app.log"
}
setup_logging(**logging_config)
出力:
ログ設定: レベル=DEBUG, 形式=%(asctime)s - %(message)s
ファイル出力: app.log
2. テストデータでの活用
def validate_user_data(username, email, age, active=True):
errors = []
if len(username) < 3:
errors.append("ユーザー名が短すぎます")
if "@" not in email:
errors.append("メールアドレスが無効です")
if age < 0:
errors.append("年齢が無効です")
return {"valid": len(errors) == 0, "errors": errors}
# テストケース
test_cases = [
{"username": "user1", "email": "user1@example.com", "age": 25},
{"username": "u", "email": "invalid-email", "age": -5},
{"username": "validuser", "email": "valid@example.com", "age": 30, "active": False}
]
for i, test_data in enumerate(test_cases, 1):
result = validate_user_data(**test_data)
print(f"テスト{i}: {'成功' if result['valid'] else '失敗'}")
if result['errors']:
for error in result['errors']:
print(f" - {error}")
出力:
テスト1: 成功
テスト2: 失敗
- ユーザー名が短すぎます
- メールアドレスが無効です
- 年齢が無効です
テスト3: 成功
3. デコレータでの活用
def retry_on_error(max_retries=3):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except Exception as e:
print(f"試行 {attempt + 1} 失敗: {e}")
if attempt == max_retries - 1:
raise
return None
return wrapper
return decorator
@retry_on_error(max_retries=2)
def unreliable_function(x, y, should_fail=False):
if should_fail:
raise ValueError("意図的なエラー")
return x + y
# 引数を展開して呼び出し
args = [10, 5]
kwargs = {"should_fail": False}
result = unreliable_function(*args, **kwargs)
print(f"結果: {result}")
出力:
結果: 15
まとめ
Python引数展開(アンパック)は以下の場面で特に有用です:
- 設定管理: 辞書やリストで管理した設定を関数に渡す
- 動的関数呼び出し: 実行時に決定される引数で関数を呼び出す
- テストデータ: 複数のテストケースを効率的に実行
- APIラッパー: 外部APIの呼び出しパラメータを管理
- データ処理: 構造化されたデータを関数に渡す
重要なポイント:
*:リスト・タプルを位置引数として展開**:辞書をキーワード引数として展開- 引数の数や名前の一致に注意
- エラーハンドリングを適切に行う
引数展開を使いこなすことで、より柔軟で保守性の高いPythonコードを書くことができます。実際にコードを書いて、この便利な機能をマスターしましょう。
関連キーワード
- Python 引数展開
- Python アンパック
- Python * **
- リスト展開 Python
- 辞書展開 Python
- タプル展開 Python
- Python 可変長引数
- args kwargs 展開
- Python アスタリスク
- 引数 アンパック
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座

