Pythonの*
と**
は、値の「展開(アンパッキング)」を直感的かつ簡潔に書ける強力な記法です。
配列の余りを受け取ったり、複数のコレクションを一気に結合したり、関数呼び出しで位置引数やキーワード引数を柔軟に組み立てたりできます。
知っておくとコードの見通しが良くなり、バグの温床になりがちなボイラープレートが激減します。
以下の表は、アンパッキングでよく使う場面のざっくり対応表です。
用途 | 記法 | 主な対象 |
---|---|---|
代入の余り取り | a, * rest | シーケンス |
コンテナ結合 | [ a, b], ( t1, t2), { s1, s2} | list, tuple, set |
関数に展開して渡す | func(* args), func(** kwargs) | 位置・キーワード引数 |
辞書のマージ | { base, override} | dict |
注: コンテナリテラルでのアンパッキング一般化はPython 3.5+で利用できます。
代入で使う*アンパッキング
余りをまとめて受け取る(a, *rest)
使いどころ
先頭だけ個別に取り、残りをまとめて取りたい場面に便利です。
余りはリストとして受け取られます(右辺がタプルでもリストになります)。
# 先頭をaに、残りをrest(リスト)に入れる
a, *rest = [10, 20, 30, 40]
print(a, rest)
# 要素が1つだけの場合、restは空リストになる
a1, *rest1 = [99]
print(a1, rest1)
# 右辺がタプルでもOK。restは常にlist
x, *xs = (1, 2, 3)
print(type(xs), xs)
10 [20, 30, 40]
99 []
<class 'list'> [2, 3]
補足
同じ代入パターン内で使える*
は1つだけです。
複数使うとSyntaxErrorになります。
末尾だけ取り出す(*head, tail)
使いどころ
最後の要素だけ別扱いにし、それ以外をまとめて受け取りたい時に使います。
# 最後の1要素をtailに、それ以外をheadに
*head, tail = [1, 2, 3, 4]
print(head, tail)
# 要素が1つだけなら、headは空リスト
*head1, tail1 = [42]
print(head1, tail1)
[1, 2, 3] 4
[] 42
補足
先頭パターン(a, *rest)と末尾パターン(*head, tail)は対称的で、どちらも覚えておくと便利です。
先頭と末尾を同時に(first, *middle, last)
使いどころ
両端を固定で取りつつ、真ん中の可変長部分をまとめたい時に最短で書けます。
first, *middle, last = [10, 20, 30, 40]
print(first, middle, last)
# 真ん中が空になる最小ケース(要素が2つ)
f2, *m2, l2 = [7, 8]
print(f2, m2, l2)
10 [20, 30] 40
7 [] 8
補足
真ん中の要素が不足しても、両端の変数を満たせないとValueErrorになります。
リスト長の可能性を把握して使いましょう。
いらない値は捨てる(*_の慣習)
使いどころ
不要な値を「使わない」意図を明示できます。
読み手にやさしい無視の明示になります。
# 2番目の値は使わない
a, _, c = [1, 2, 3]
print(a, c)
# 真ん中の連続した値をすべて無視(慣習的に "_" を使う)
start, *_, end = [100, 200, 300, 400, 500]
print(start, end)
1 3
100 500
補足
「_」は捨てる目的を示す変数名です。
実体は通常の変数なので、同じスコープで再利用しないように注意します。
forループでも使える(for x, *rest in rows)
使いどころ
可変長のタプルやリストのシーケンスをループで処理する時、先頭と残りを綺麗に分けられます。
rows = [
("alice", 80, 90, 70),
("bob", 100, 95),
("carol", 60),
]
for name, *scores in rows:
# scoresは可変長のリスト。平均を安全に計算
avg = sum(scores) / len(scores) if scores else 0
print(f"{name}: count={len(scores)} avg={avg:.1f}")
alice: count=3 avg=80.0
bob: count=2 avg=97.5
carol: count=1 avg=60.0
補足
左辺の分解は代入と同じルールです。
ループ対象の各要素(右辺)の形が想定と一致しているかを意識しましょう。
コレクション操作で使う*アンパッキング
リスト結合をシンプルに([*a, *b, x])
使いどころ
リストを複数結合し、さらに値を足す時に+
やextend()
より読みやすく書けます。
a = [1, 2]
b = [3, 4]
x = 99
merged = [*a, *b, x]
print(merged)
[1, 2, 3, 4, 99]
補足
作られるのは新しいリストです。
原リストa
やb
は変更されません。
リストのコピーを手早く([*a])
使いどころ
浅いコピー(シャローコピー)を最短で取りたい時に使えます。
a = [[1], [2]]
copy1 = [*a] # 浅いコピー
copy2 = a[:] # これも浅いコピー
print("== equality:", copy1 == a)
print("is same object:", copy1 is a)
# 浅いコピーなのでネストは共有される
a[0].append(999)
print("after mutate nested:", a, copy1)
== equality: True
is same object: False
after mutate nested: [[1, 999], [2]] [[1, 999], [2]]
補足
深いコピーが必要ならcopy.deepcopy()
を検討してください。
アンパッキングはあくまで浅いコピーです。
タプルも結合できる((*t1, *t2))
使いどころ
タプルを結合しつつ、最後に定数を足すなどの複合操作を1行で書けます。
t1 = (1, 2)
t2 = (3,)
combined = (*t1, *t2, 4)
print(combined, type(combined))
(1, 2, 3, 4) <class 'tuple'>
補足
括弧で囲めばタプルリテラルの中でも*
展開が使えます。
タプルは不変(immutable)なので新しいタプルが生成されます。
セットをまとめる({*s1, *s2})
使いどころ
重複を排除しつつ複数の集合をまとめたい時、|
(和集合)の代わりにリテラルで直感的に書けます。
s1 = {1, 2}
s2 = {2, 3, 4}
merged = {*s1, *s2}
print(merged)
{1, 2, 3, 4}
補足
セットは順序を持たないため、出力順は未定義です。
順序が大事ならリストに変換してソートしましょう。
イテラブルを一気にリスト化([*range(10)])
使いどころ
ジェネレータやrangeなど複数のイテラブルを、一度に評価して1つのリストにするのに便利です。
def gen():
# 0, 4, 16 を順に生成するジェネレータ
for i in range(3):
yield i * i
lst = [*range(3), *gen(), 99]
print(lst)
[0, 1, 2, 0, 1, 4, 99]
補足
巨大なイテラブルを展開すると全要素をメモリに載せるため注意してください。
ストリーミング処理が必要ならジェネレータのまま扱うのが無難です。
関数で使う*と**のアンパッキング
シーケンスを引数に展開して渡す(func(*args))
使いどころ
既にリストやタプルに入っている値を、位置引数としてそのまま渡す時に使います。
def add(a, b, c):
return a + b + c
args = [1, 2, 3]
print(add(*args)) # add(1, 2, 3) と同じ
6
補足
引数個数は関数のシグネチャと一致させる必要があります。
不足や過剰があるとTypeErrorになります。
辞書をキーワード引数に展開(func(**params))
使いどころ
オプション集合をdictで持っていて、関数のキーワード引数に展開して渡したい時に便利です。
def connect(host, port, use_ssl=False):
print(f"host={host}, port={port}, use_ssl={use_ssl}")
params = {"host": "example.com", "port": 443, "use_ssl": True}
connect(**params)
host=example.com, port=443, use_ssl=True
補足
辞書のキーは関数の引数名と一致している必要があります。
余分なキーや不足はTypeErrorになります。
位置とキーワードを合わせて展開(func(a, *xs, b=1, **kw))
使いどころ
固定値・可変位置引数・任意のキーワード引数を柔軟に合成できます。
API呼び出しの薄いラッパー実装で重宝します。
def show(a, b, c=0, d=0, **kw):
print(f"a={a}, b={b}, c={c}, d={d}, extras={kw}")
xs = [20] # bに入る
kw = {"d": 4, "note": "ok"}
show(10, *xs, c=3, **kw)
a=10, b=20, c=3, d=4, extras={'note': 'ok'}
補足
同じ引数を重複指定するとTypeErrorです(例: c=3
とkw={'c': 9}
を同時に渡す)。
printで見やすく出力(print(*items, sep=”, “))
使いどころ
配列の中身を区切って一気に表示したい時に、print()
のsep
と組み合わせるとすっきり書けます。
items = ["apple", "banana", "cherry"]
print(*items, sep=", ")
apple, banana, cherry
補足
endやfileといった他の引数とも併用できます。
デバッグ時にも便利です。
- 関連記事:print()の使い方と基本の表示サンプル集
- 関連記事:printで改行しない方法: end=”で連続出力
- 関連記事:f-stringで変数名と値を同時出力 f'{var=}’の使い方
- print() — Python 3.13.7 ドキュメント
辞書をマージして設定を上書き({**base, **override})
使いどころ
基本設定に対して、後勝ちで部分的に上書きしたい時に最短で書けます。
base = {"timeout": 30, "retry": 2, "mode": "safe"}
override = {"retry": 5, "verbose": True}
merged = {**base, **override}
print(merged)
{'timeout': 30, 'retry': 5, 'mode': 'safe', 'verbose': True}
補足
後に書いた辞書が優先されます。
Python 3.9+ではbase | override
という集合風の書き方もできます。
ネストした辞書は深くマージされない点に注意してください(必要なら専用関数を用意します)。
まとめ
アンパッキングは「読む・書く・直す」を楽にするPythonの表現力そのものです。
代入ではa, rest
やhead, tail
で配列の分解が明快になり、コレクション操作では[a, b]
や{**base, **override}
で新オブジェクトの構築が簡潔になります。
関数呼び出しではargs
と**kwargs
により、柔軟なインターフェース設計と再利用が進みます。
最後にもう一度要点を押さえると、「余りはリストになる」「同じパターン内でのは1つだけ」「辞書のマージは後勝ち」です。
これらを意識すれば、日常のPythonコードはより短く、より安全で、より読みやすくなります。