Python 3ではtuple
やlist
の分割にインデクサとシークエンスのアンパック(アンパック代入)の2通りが使えます。後者は慣例的なアンダースコア_
による変数の破棄(_
の使い回し)やアスタリスク*
によるイテラブルの残った要素のリストへの代入が可能です。
なお、ここではPython 3ドキュメントにあるタプルへのアンパック以外、リストへの変換もコード中で左辺の要素の一部が変数として利用できればアンパックとみなしています。
[a, b] = 0, 1
# 上式はタプルからリストへの変換だが、リストの要素bは変数として使える
print(b) # 1
b = 2
print(b) # 2
print((a, b)) # (0, 2)
前提条件
インデクサが使える型と使えない型
インデクサが使える型は__index__
抽象メソッドを持つクラスであり、使えない型は__index__
を持たない型です。前者にはtuple
やlist
のようなインデックスが意味を持つ型があり、後者にはset
やfrozenset
のようにインデックスが意味を持たない型です。後者にインデクサを使うとTypeError
エラーが発生します。
tuple1 = (0, 1, 2)
t0 = tuple1[0]
print(0) # 0
t0, t1, t2 = tuple1
print((t0, t1, t2)) # (0, 1, 2)
set1 = {0, 1, 2}
# s0 = set1[0] # TypeError 'set' object is not subscriptable
# print(s0)
s0, s1, s2 = set1
print((s0, s1, s2)) # (0, 1, 2)
__index__
を持つ型はtyping.SupportsIndexとして定義されています。
シークエンスのアンパック(アンパック代入)が使える型と使えない型
シークエンスのアンパックが使える型はsequence
に該当する型です。これは__getitem__
特殊メソッドと__len__
特殊メソッドを持つ型であり、tuple
、list
、set
等の多くの型が該当します。
インデクサもシークエンスのアンパックも使える型と使えない型
インデクサもシークエンスのアンパックも使える型は__index__
、__getitem__
、__len__
を持つ型です。tuple
やlist
はこれに該当しますが、set
やfrozenset
は該当しません。
tuple
の分割
前後の(
、)
が省略できるため、等号の左辺(アンパック先)の場合は分割して代入するように書けます。
t = ("a", "b", "c")
a = t[0]
b = t[1]
c = t[2]
print((a, b, c)) # ('a', 'b', 'c')
# tuple→tuple
a, b, c = "a", "b", "c"
print((a, b, c)) # ('a', 'b', 'c')
# tuple→tuple
a, b, c = ("a", "b", "c")
print((a, b, c)) # ('a', 'b', 'c')
# tuple→tuple
(a, b, c) = ("a", "b", "c")
print((a, b, c)) # ('a', 'b', 'c')
# 不要な変数の省略
(_, b, _) = ("a", "b", "c")
print((_, b, _)) # ('c', 'b', 'c')
# 残りをlistにまとめる
(a, *bc, _, e) = ("a", "b", "c", "d", "e")
print((a, bc, _, e)) # ('a', ['b', 'c'], 'd', 'e')
# tuple→list
[a, b, c] = ("a", "b", "c")
print((a, b, c)) # ('a', 'b', 'c')
# 不要な変数の省略
[_, b, _] = ("a", "b", "c")
print((_, b, _)) # ('c', 'b', 'c')
# 残りをlistにまとめる
[a, *bc, _, e] = ("a", "b", "c", "d", "e")
print((a, bc, _, e)) # ('a', ['b', 'c'], 'd', 'e')
list
の分割
基本的にtuple
と同様に扱えます。ただし、前後の[
、]
は省略できません。
t = ["a", "b", "c"]
a = t[0]
b = t[1]
c = t[2]
print((a, b, c)) # ('a', 'b', 'c')
# list→tuple
a, b, c = ["a", "b", "c"]
print((a, b, c)) # ('a', 'b', 'c')
# list→tuple
(a, b, c) = ["a", "b", "c"]
print((a, b, c)) # ('a', 'b', 'c')
# 不要な変数の省略
(_, b, _) = ["a", "b", "c"]
print((_, b, _)) # ('c', 'b', 'c')
# 残りをlistにまとめる
(a, *bc, _, e) = ["a", "b", "c", "d", "e"]
print((a, bc, _, e)) # ('a', ['b', 'c'], 'd', 'e')
# list→list
[a, b, c] = ["a", "b", "c"]
print((a, b, c)) # ('a', 'b', 'c')
# 不要な変数の省略
[_, b, _] = ["a", "b", "c"]
print((_, b, _)) # ('c', 'b', 'c')
# 残りをlistにまとめる
[a, *bc, _, e] = ["a", "b", "c", "d", "e"]
print((a, bc, _, e)) # ('a', ['b', 'c'], 'd', 'e')
set
の分割
インデクサは非対応です。タプルやリストにアンパックする場合、順序は保証されません。
# set→tuple
# 順序は保証されない。
a, b, c = {"a", "b", "c"}
print((a, b, c)) # ('a', 'b', 'c')の並び替えのどれか
# set→list
# 順序は保証されない。
[a, b, c] = {"a", "b", "c"}
print((a, b, c)) # ('a', 'b', 'c')の並び替えのどれか
# set→set(できない)
# {a, b, c} = {"a", "b", "c"}
# print((a, b, c)) # ('a', 'c', 'b')