はじめに
Pythonを学んでいる中で、「複数同時の代入」という構文に出会った。最初は「そういうものがあるのか」くらいの感想だったが、掘ってみるとなかなか興味深く、この記事ではその仕組みについて紹介したい。初心者が書いた初心者向けの記事である。
「複数同時の代入」の基本構文
以下のようなaに1、bに2を代入するコードがあるとする。
a = 1
b = 2
print(a)
print(b)
1
2
この場合、a, b = 1, 2のように一行で記載することで、一度に複数の変数に代入できる。これが「複数同時の代入」の基本構文である。
a, b = 1, 2
print(a)
print(b)
1
2
活用例の一つとして、値の入れ替えを簡潔に書けるという点がある。以下の例ではxに3、yに4を代入した後、xとyの値を入れ替えている。通常このような操作には一時的に値を退避させるための変数が別途必要になるが、複数同時の代入を使えば極めて簡潔に書くことができる。
x, y = 3, 4
x, y = y, x
print(x)
print(y)
4
3
ところで、公式ドキュメントには「複数同時の代入」について以下のような記載がなされている。これがどういうことなのかを、本記事では解説していく。
複数同時の代入が実はタプルのパックとシーケンスのアンパックを組み合わせたものに過ぎないことに注意してください。
タプルのパック
Pythonでは各要素をカンマ区切りで記載し、角括弧で囲うとリスト、括弧でタプル、波括弧で集合として一つのデータ構造にまとめる(パックする)ことが出来る。
# リスト
a = ['apple', 'banana', 'cherry']
# タプル
b = ('apple', 'banana', 'cherry')
# 集合
c = {'apple', 'banana', 'cherry'}
print(type(a))
print(type(b))
print(type(c))
<class 'list'>
<class 'tuple'>
<class 'set'>
ここで、括弧を省略した場合はタプルとしてパックされる。
# 括弧を省略した場合はタプルになる
d = 'apple', 'banana', 'cherry'
print(type(d))
<class 'tuple'>
この括弧で括らずにカンマ区切りで並べて記載するという形は、基本構文の項で紹介した「複数同時の代入」の右辺と同じ形である。つまり、ここではタプルのパックの仕組みが使われているということになる。
# 右辺の1と2はタプルとしてパックされている
a, b = 1, 2
print(a)
print(b)
シーケンスのアンパック
Pythonでは左辺の変数の数と右辺の要素の数が一致していれば、タプルやリストなどのシーケンス(順序を持つデータ構造)を、複数の変数に展開することができる。1
# dに3つの要素を入れたタプルを定義
d = ('apple', 'banana', 'cherry')
# x,y,zの3つの変数にdのタプルを展開
x, y, z = d
print(x)
print(y)
print(z)
apple
banana
cherry
上記のコードでは各要素を一度変数dに入れているが、直接x,y,zに代入することも可能である。そして、タプルの括弧も省略すると、「複数同時の代入」の構文と同じ形になる。
x, y, z = 'apple', 'banana', 'cherry'
print(x)
print(y)
print(z)
apple
banana
cherry
おわりに
これらを踏まえると、以下のコードでは右辺の1, 2というカンマ区切りの要素は一つのタプルとしてパックされ、そして左辺の変数a、bにパックされた要素(1,2)が順番にアンパックされ代入されるということになる。
a, b = 1, 2
print(a)
print(b)
つまり、公式ドキュメントの記載通り、「複数同時の代入」という専用の仕組みがあるわけではなく、タプルのパックとシーケンスのアンパックという2つの仕組みによって「複数同時の代入」が成り立っているということになる。なるほどなぁ。
実行環境
参考記事
-
Python3からはアスタリスクを使った拡張アンパックにより、変数の数が要素の数よりも少ない場合でも余った要素をまとめてリストとして代入するということも出来る。 ↩