タイトル: タプルの作成
SEOタイトル: Pythonタプル作成完全ガイド(単一要素/unpacking/namedtuple/辞書キー)
| この記事の要点 |
|
タプルとは
タプル(tuple)は順序を持つ不変なシーケンスです。リストとほぼ同じく使えますが、作成後に要素を変更できません。括弧 () で表記しますが、本質的にはカンマで区切ることで作られます。
# 基本: 括弧で囲む
t1 = (1, 2, 3)
# 実は括弧は必須ではない(カンマがタプルを作る)
t2 = 1, 2, 3
print(type(t2)) #
# 空タプル
t3 = ()
t4 = tuple()
単一要素タプルの罠
1 要素のタプルは 末尾カンマが必須です。これは初学者が最も間違えるポイント:
# ❌ これは int の 1(タプルではない)
x = (1)
print(type(x)) #
# ✅ 末尾カンマで単一要素タプル
y = (1,)
print(type(y)) #
# ✅ 括弧不要でも OK
z = 1,
print(type(z)) #
# 文字列でも同様
s1 = ('hello') # str
s2 = ('hello',) # tuple
tuple() で iterable から変換
# リストから
tuple([1, 2, 3]) # (1, 2, 3)
# 文字列から(文字単位に分解)
tuple("abc") # ('a', 'b', 'c')
# range から
tuple(range(5)) # (0, 1, 2, 3, 4)
# ジェネレータから
tuple(x * 2 for x in range(3)) # (0, 2, 4)
# 辞書から(キーのみ)
tuple({'a': 1, 'b': 2}) # ('a', 'b')
# 辞書から(items)
tuple({'a': 1, 'b': 2}.items()) # (('a', 1), ('b', 2))
アンパック(unpacking)
タプルは複数代入と同時に分解できます。Python の慣用句として広く使われます。
# 基本のアンパック
a, b = (1, 2)
print(a, b) # 1 2
# 入れ子もOK
(a, b), c = (1, 2), 3
# スワップ
a, b = b, a
# 関数の複数戻り値
def divmod_(a, b):
return a // b, a % b # タプルが返る
q, r = divmod_(17, 5) # 自動的にアンパック
# 拡張アンパック(PEP 3132、Python 3+)
first, *rest = (1, 2, 3, 4, 5)
# first=1, rest=[2, 3, 4, 5]
first, *middle, last = (1, 2, 3, 4, 5)
# first=1, middle=[2, 3, 4], last=5
# 値を捨てる
_, value = ('key', 100)
namedtuple / NamedTuple
位置だけでなく名前でアクセスしたいときに使います。データクラスより軽量、辞書よりタイプセーフ。
# 方法1: collections.namedtuple
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x, p.y) # 1 2
print(p[0], p[1]) # 1 2 (位置でも OK)
# 方法2: typing.NamedTuple(型ヒント付き、3.6+)
from typing import NamedTuple
class User(NamedTuple):
name: str
age: int
email: str = "" # デフォルト値もOK
def is_adult(self) -> bool: # メソッドも定義可
return self.age >= 18
u = User(name="Alice", age=30)
print(u.is_adult()) # True
# unpacking
name, age, email = u
辞書のキー・集合の要素になれる
タプルはハッシュ可能(immutable)なので、辞書のキーや集合の要素として使えます。リストは使えません。
# 座標をキーにしたグリッド
grid = {}
grid[(0, 0)] = "start"
grid[(1, 2)] = "treasure"
# 集合
visited = set()
visited.add((0, 0))
visited.add((1, 2))
# ❌ リストはハッシュ不可
# d = {[1, 2]: "x"} # TypeError: unhashable type: 'list'
# 注意: タプル内に list があるとハッシュ不可になる
hash((1, 2, 3)) # OK
hash((1, [2, 3])) # TypeError
タプル同士の比較
タプル同士は辞書順で比較されます。最初の要素で決着がつけばそこで決定、同じなら次の要素を見ます。
(1, 2) < (1, 3) # True (2 < 3)
(1, 2) < (2, 0) # True (1 < 2)
(1, 2, 3) < (1, 2) # False (前者の方が長い)
(1, 2) == (1, 2) # True
# ソートで便利
people = [("Alice", 30), ("Bob", 25), ("Carol", 30)]
people.sort()
# [('Alice', 30), ('Bob', 25), ('Carol', 30)]
# → 名前優先、同名なら年齢順
# 第二キーで降順したい時
people.sort(key=lambda p: (p[1], p[0]))
タプルとリストの使い分け
| 用途 | 推奨 |
|---|---|
| 異なる種類の要素のまとまり (record 的) | タプル / namedtuple |
| 同種要素の集まり(後から追加削除) | リスト |
| 関数の複数戻り値 | タプル |
| 辞書のキー・集合の要素 | タプル必須 |
| 関数のデフォルト引数で空コレクション | タプル(mutable default の罠回避) |
FAQ
Q: タプルとリストどっちが速い?
A: 微妙にタプルの方が高速・小メモリですが、現代の Python では誤差レベル。意味で選ぶべきです。
Q: タプルの要素を変更したい
A: 不可能。list(t) で一旦リスト化 → 変更 → tuple(...) で戻すか、新しいタプルを作ります。
Q: 関数の引数のデフォルト値に空リストはなぜダメ?
A: ミュータブル既定値の罠。def f(x=[]) は呼び出し間で共有されます。def f(x=()) または def f(x=None): x = x or [] を使ってください。