閉じる

*と**で広がるPythonアンパッキング 便利ワザ15選

Pythonの***は、値の「展開(アンパッキング)」を直感的かつ簡潔に書ける強力な記法です。

配列の余りを受け取ったり、複数のコレクションを一気に結合したり、関数呼び出しで位置引数やキーワード引数を柔軟に組み立てたりできます。

知っておくとコードの見通しが良くなり、バグの温床になりがちなボイラープレートが激減します。

以下の表は、アンパッキングでよく使う場面のざっくり対応表です。

用途記法主な対象
代入の余り取りa, *restシーケンス
コンテナ結合[a, b], (t1, t2), {s1, s2}list, tuple, set
関数に展開して渡すfunc(*args), func(**kwargs)位置・キーワード引数
辞書のマージ{base, override}dict

: コンテナリテラルでのアンパッキング一般化はPython 3.5+で利用できます。

代入で使う*アンパッキング

余りをまとめて受け取る(a, *rest)

使いどころ

先頭だけ個別に取り、残りをまとめて取りたい場面に便利です。

余りはリストとして受け取られます(右辺がタプルでもリストになります)。

Python
# 先頭を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)

使いどころ

最後の要素だけ別扱いにし、それ以外をまとめて受け取りたい時に使います。

Python
# 最後の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)

使いどころ

両端を固定で取りつつ、真ん中の可変長部分をまとめたい時に最短で書けます。

Python
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になります

リスト長の可能性を把握して使いましょう。

いらない値は捨てる(*_の慣習)

使いどころ

不要な値を「使わない」意図を明示できます。

読み手にやさしい無視の明示になります。

Python
# 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)

使いどころ

可変長のタプルやリストのシーケンスをループで処理する時、先頭と残りを綺麗に分けられます。

Python
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()より読みやすく書けます。

Python
a = [1, 2]
b = [3, 4]
x = 99

merged = [*a, *b, x]
print(merged)
実行結果
[1, 2, 3, 4, 99]

補足

作られるのは新しいリストです。

原リストabは変更されません。

リストのコピーを手早く([*a])

使いどころ

浅いコピー(シャローコピー)を最短で取りたい時に使えます。

Python
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行で書けます。

Python
t1 = (1, 2)
t2 = (3,)
combined = (*t1, *t2, 4)
print(combined, type(combined))
実行結果
(1, 2, 3, 4) <class 'tuple'>

補足

括弧で囲めばタプルリテラルの中でも*展開が使えます

タプルは不変(immutable)なので新しいタプルが生成されます。

セットをまとめる({*s1, *s2})

使いどころ

重複を排除しつつ複数の集合をまとめたい時、|(和集合)の代わりにリテラルで直感的に書けます。

Python
s1 = {1, 2}
s2 = {2, 3, 4}
merged = {*s1, *s2}
print(merged)
実行結果
{1, 2, 3, 4}

補足

セットは順序を持たないため、出力順は未定義です。

順序が大事ならリストに変換してソートしましょう。

イテラブルを一気にリスト化([*range(10)])

使いどころ

ジェネレータやrangeなど複数のイテラブルを、一度に評価して1つのリストにするのに便利です。

Python
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))

使いどころ

既にリストやタプルに入っている値を、位置引数としてそのまま渡す時に使います。

Python
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で持っていて、関数のキーワード引数に展開して渡したい時に便利です。

Python
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呼び出しの薄いラッパー実装で重宝します。

Python
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=3kw={'c': 9}を同時に渡す)。

printで見やすく出力(print(*items, sep=”, “))

使いどころ

配列の中身を区切って一気に表示したい時に、print()sepと組み合わせるとすっきり書けます。

Python
items = ["apple", "banana", "cherry"]
print(*items, sep=", ")
実行結果
apple, banana, cherry

補足

endfileといった他の引数とも併用できます。

デバッグ時にも便利です。

辞書をマージして設定を上書き({**base, **override})

使いどころ

基本設定に対して、後勝ちで部分的に上書きしたい時に最短で書けます。

Python
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, resthead, tailで配列の分解が明快になり、コレクション操作では[a, b]{**base, **override}で新オブジェクトの構築が簡潔になります。

関数呼び出しではargs**kwargsにより、柔軟なインターフェース設計と再利用が進みます。

最後にもう一度要点を押さえると、「余りはリストになる」「同じパターン内でのは1つだけ」「辞書のマージは後勝ち」です。

これらを意識すれば、日常のPythonコードはより短く、より安全で、より読みやすくなります。

Python 実践TIPS - コーディング効率化・Pythonic
この記事を書いた人
エーテリア編集部
エーテリア編集部

人気のPythonを初めて学ぶ方向けに、文法の基本から小さな自動化まで、実際に手を動かして理解できる記事を書いています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!