Python講座 / タプルとシーケンスのアンパックを理解する

タプルは順序を持ち、各位置が参照する要素を差し替えられないシーケンスです。短いレコードや複数の戻り値に使えますが、中に入れたリストなどの内容まで固定されるわけではありません。

作り方と変更できない範囲を確かめる

タプルを作るのはコンマで、かっこはまとまりを読みやすくする役割も持ちます。一要素なら(3500,)のように末尾のコンマが必要です。(3500)は整数の式であり、同じ意味にはなりません。

single = (3500,)
record = ("lunch", 8000)
print(type(single).__name__)
print(record[0])

1行目はtuple、2行目はlunchです。タプルにリストを入れた場合、その位置を別のリストへ差し替えることはできなくても、入っているリストの中身は変更できます。「外側が不変」と「入れ子の全データが不変」を分けてください。

アンパックの全体例を動かす

tuples.pyへ次のコードを保存し、仮想環境でpython tuples.pyを実行します。アンパックは要素を複数の名前へまとめて割り当てる処理です。

record = ("lunch", 8000, "food")
name, amount, category = record
print(name, amount, category)
first, *rest = [3500, 8000, 2500]
print(first, rest)
a, b = 1, 2
a, b = b, a
print(a, b)

予想される出力です。最後の二変数は一度の代入で値を交換しています。

lunch 8000 food
3500 [8000, 2500]
2 1

要素の数と意味を合わせる

普通の名前へ展開する場合、右辺の要素数と左辺の名前の数が一致しなければValueErrorになります。*restのようなターゲットは余りをリストとして受け取り、一つのアンパック代入に指定できるスター付きターゲットは一つです。

辞書をそのまま反復すると得られるのはキーです。キーと値を一緒に取り出すならitems()を使います。外部ファイルやネットワーク由来のデータでは、すべての行が同じ項目数だと決めつける前に、構造を確認してください。

リスト・タプル・名前付き項目を使い分ける

必要な性質 選択肢
増えていく金額の列 リスト
位置の意味が明確な短いレコード タプル
名前で識別する項目 辞書やdataclass

タプルを辞書のキーにできるのは、すべての要素がハッシュ可能な場合です。リストを含むタプルはその条件を満たしません。不変な外側だけで判断しないようにします。

recordからcategoryを削って展開の失敗を観察し、受け取る名前の数を合わせたら元のレコードへ戻します。位置の意味を覚えにくくなった場合は、辞書やdataclassで項目名を表す方が、データの意味を伝えやすくなります。

タプルの不変性は、要素が参照する対象を再代入できないという意味です。pair = ([1], 2) で pair[0] = [] は失敗しますが、pair[0].append(3) は成功し、結果は ([1, 3], 2) です。タプル内のデータまですべて不変になるわけではありません。

関連する公式リファレンス