この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:6
ページ更新者:T
更新日時:2026-06-11 07:07:02

タイトル: タプル
SEOタイトル: Python タプル型完全ガイド

この記事の要点
  • タプル (tuple) は Python の不変 (immutable) なシーケンス型。(1, 2, 3)
  • 不変なのでハッシュ可能: dict のキー / set の要素として使える (リストは不可)
  • a, b = (1, 2) でアンパック、*rest で残りをまとめてキャプチャ
  • 名前付きフィールドが欲しいときは collections.namedtuple or typing.NamedTuple
  • 型注釈: Python 3.9+ は tuple[int, str]、それ以前は typing.Tuple[int, str]

タプルとは

Python の タプル (tuple) は、複数の値を順序付きで格納する不変 (immutable) のシーケンス型です。リスト (list) と似ていますが、作成後に要素を変更できない点が決定的に異なります。

タプルの作り方

# 基本: 括弧で囲んでカンマ区切り
t = (1, 2, 3)
t = (1, 'hello', 3.14, True)         # 異なる型も混在可

# 括弧は省略可 (カンマがあればタプル)
t = 1, 2, 3
print(type(t))                        # 

# 空タプル
empty = ()
empty = tuple()

# ★ 注意: 要素 1 個のタプルは末尾カンマ必須
single = (1,)                         # タプル
not_tuple = (1)                       # ただの int

# イテラブルから生成
t = tuple([1, 2, 3])                  # (1, 2, 3)
t = tuple('hello')                    # ('h', 'e', 'l', 'l', 'o')
t = tuple(range(5))                   # (0, 1, 2, 3, 4)

不変性 (Immutability)

t = (1, 2, 3)

# ❌ 要素の変更は不可
t[0] = 99
# → TypeError: 'tuple' object does not support item assignment

# ❌ append / pop も無い
t.append(4)
# → AttributeError

# ✅ 新しいタプルを作る
t2 = t + (4,)         # (1, 2, 3, 4)
t3 = (0,) + t          # (0, 1, 2, 3)
t4 = t * 3             # (1, 2, 3, 1, 2, 3, 1, 2, 3)

# 注意: タプルが「含む」オブジェクトが mutable なら中身は変えられる
t = ([1, 2], [3, 4])
t[0].append(99)        # OK ((リストは mutable))
print(t)               # ([1, 2, 99], [3, 4])

ハッシュ可能 (Hashable) という強力な性質

タプルが不変であることの最大の効用は、ハッシュ可能であることです。これにより dict のキーや set の要素として使えます (リストは不可)。

# 座標を dict のキーに使う
grid = {}
grid[(0, 0)] = 'start'
grid[(10, 5)] = 'enemy'
print(grid[(0, 0)])                  # 'start'

# 複合キーで集計
sales = {}
sales[('Tokyo', '2025-01')] = 1000
sales[('Tokyo', '2025-02')] = 1200
sales[('Osaka', '2025-01')] = 800

# set の要素
visited = set()
visited.add((3, 4))
visited.add((3, 4))                  # 重複は無視
print(len(visited))                  # 1

# ❌ リストはキーにできない
{[1, 2]: 'value'}
# → TypeError: unhashable type: 'list'

アンパック (Unpacking)

# 基本のアンパック
t = (1, 2, 3)
a, b, c = t
print(a, b, c)                        # 1 2 3

# 関数の複数戻り値 (実はタプル)
def divmod_fn(a, b):
    return a // b, a % b              # タプルとして返している

q, r = divmod_fn(10, 3)
print(q, r)                           # 3 1

# * で残りをキャプチャ (PEP 3132)
first, *rest = (1, 2, 3, 4, 5)
print(first)                          # 1
print(rest)                           # [2, 3, 4, 5] ← list

*init, last = (1, 2, 3, 4, 5)
print(init)                           # [1, 2, 3, 4]
print(last)                           # 5

first, *middle, last = (1, 2, 3, 4, 5)
print(first, middle, last)            # 1 [2, 3, 4] 5

# 値のスワップ (右辺がタプルとして評価される)
a, b = 1, 2
a, b = b, a
print(a, b)                           # 2 1

# 関数呼び出しでアンパック
def add(x, y, z):
    return x + y + z

args = (1, 2, 3)
print(add(*args))                     # 6

namedtuple (名前付きタプル)

位置だけでなくフィールド名でアクセスできるタプル。クラスより軽量で、データ構造表現に最適。

from collections import namedtuple

# 定義
Point = namedtuple('Point', ['x', 'y'])
# または文字列でも可: Point = namedtuple('Point', 'x y')

# 生成
p = Point(10, 20)
print(p.x, p.y)                       # 10 20
print(p[0], p[1])                     # 10 20 (位置でもアクセス可)

# アンパックも可
x, y = p
print(x, y)                           # 10 20

# 不変性は維持
p.x = 99
# → AttributeError: can't set attribute

# 一部だけ書き換えた新インスタンス
p2 = p._replace(x=99)                 # Point(x=99, y=20)

# 辞書化
print(p._asdict())                    # {'x': 10, 'y': 20}

# 全フィールド名
print(Point._fields)                  # ('x', 'y')

typing.NamedTuple (型注釈付き)

from typing import NamedTuple

class Point(NamedTuple):
    x: int
    y: int
    label: str = 'origin'             # デフォルト値も可

p = Point(10, 20)
print(p)                              # Point(x=10, y=20, label='origin')

p2 = Point(x=1, y=2, label='A')

# メソッド定義もできる
class Circle(NamedTuple):
    center: Point
    radius: float

    def area(self) -> float:
        return 3.14159 * self.radius ** 2

c = Circle(Point(0, 0), 5.0)
print(c.area())                       # 78.5398

型注釈

# Python 3.9+ (PEP 585)
def process(pair: tuple[int, str]) -> tuple[int, int]:
    return pair[0], len(pair[1])

# Python 3.8 以前
from typing import Tuple
def process(pair: Tuple[int, str]) -> Tuple[int, int]:
    return pair[0], len(pair[1])

# 可変長
coords: tuple[int, ...] = (1, 2, 3, 4, 5)   # int の任意個

# 固定の組み合わせ
rgb: tuple[int, int, int] = (255, 128, 0)

タプル vs リストの使い分け

用途タプルリスト
変更しない固定データ★ 推奨×
異種混在の構造体的データ (座標 / レコード)★ 推奨不可
同種要素のコレクション (動的に追加)×★ 推奨
dict のキー / set の要素★ 必須不可 (unhashable)
関数の複数戻り値★ 慣例×
メモリ効率やや小 (固定サイズ)余裕領域あり

メモリ効率の比較

import sys

t = (1, 2, 3, 4, 5)
l = [1, 2, 3, 4, 5]

print(sys.getsizeof(t))               # 80 bytes
print(sys.getsizeof(l))               # 104 bytes

# タプルは大量生成しても効率的
# 列挙型代わりに、ループ内で生成しても OK

よくあるパターン

# enumerate: (index, value) のタプルを返す
for i, name in enumerate(['Alice', 'Bob']):
    print(f'{i}: {name}')

# zip: 複数イテラブルを (a, b, c) のタプルに
for a, b in zip([1, 2, 3], ['a', 'b', 'c']):
    print(a, b)

# 辞書のキー・値のペア
d = {'a': 1, 'b': 2}
for k, v in d.items():                # items() は (key, value) のタプル
    print(k, v)

# pandas / numpy のシェイプ
import numpy as np
arr = np.zeros((3, 4, 5))             # shape は tuple
print(arr.shape)                       # (3, 4, 5)

FAQ

Q: タプルとリストはどちらを選ぶべき?
A: 「変更しない固定のデータ」「異なる型のフィールドを持つレコード」はタプル、「動的に増減する同種コレクション」はリスト。複数戻り値や dict キーは必然的にタプル。

Q: x = (1) がタプルにならない
A: 括弧は単なるグルーピング演算子。要素 1 個のタプルは (1,) と末尾カンマが必要です。空タプルだけは () でも OK。

Q: namedtuple と dataclass のどちらを使う?
A: イミュータブルで軽量な構造体は namedtuple、ミュータブルでメソッドも持つクラスは dataclass。Python 3.7+ で @dataclass(frozen=True) で不変 dataclass も作れる。