TL;DR
イテラブルの値の数が、代入の左辺の変数の数より多い場合に発生します。変数を追加して数を合わせるか、*restを使って余分な値を吸収するか、アンパック対象を修正してください。
# エラーになるコード
a, b = (1, 2, 3) # ValueError: too many values to unpack (expected 2)
# 修正済み — 数を合わせる
a, b, c = (1, 2, 3)
# 修正済み — スターで余分な値を収集
a, b, *rest = (1, 2, 3, 4, 5) # rest = [3, 4, 5]
根本原因
Pythonのアンパックは位置指定です。左辺の変数の数は、右辺の値の数と正確に一致する必要があります。値が1つ多いだけで ValueError: too many values to unpack (expected N) が発生します。
最も多く発生する4つの状況:
- タプルやリストを、それが含む値より少ない変数に代入する
.items()なしで辞書をイテレートする — 各キーが文字のイテラブルとして扱われる- 想定外のフィールドが含まれるCSV行やAPIレスポンスをアンパックする
- 各要素が3つ以上のアイテムを持つ場合に
for a, b in some_listを使用する
修正1 — 変数の数を合わせる
値の数を数えて、正しい数の変数を宣言します。リテラルの場合は明らかですが、自分で書いたものではなく関数呼び出しからデータが来る場合は見落としやすいです。
# エラーになるコード
first, last = "John", "Paul", "George", "Ringo"
# 正しいコード
first, second, third, fourth = "John", "Paul", "George", "Ringo"
常に正確な数が事前にわかっている固定構造に適しています。
修正2 — スター(*) 構文を使って全て受け取る
特定の位置だけが必要な場合は、* で残りをリストに吸収させます:
# 最初と最後を取得し、中間を収集
first, *middle, last = [10, 20, 30, 40, 50]
print(first) # 10
print(last) # 50
print(middle) # [20, 30, 40]
# 最初の2つを取得し、残りを破棄
a, b, *_ = get_csv_row() # _ は破棄の慣例
スター構文は可変長データをきれいに処理します — CSV行、APIペイロード、予告なく余分なフィールドが現れる可能性がある全てのデータに対応します。*_ パターンは「もっとあることはわかっているが、必要ない」というPythonの慣用的な表現です。
修正3 — .items()なしの辞書イテレーション
多くの人がはまるケースです。.items()なしで辞書をイテレートすると、(key, value)ペアではなくキーが得られます。キーが"name"のような文字列の場合、Pythonは4つの個別文字として認識し、2つの変数へのアンパックは即座に失敗します:
# エラーになるコード — (key, value)ペアではなくキーをイテレートする
data = {"name": "Alice", "age": 30}
for key, value in data: # ValueError: "name" は4文字で2文字ではない
print(key, value)
# 修正済み
for key, value in data.items():
print(key, value)
# name Alice
# age 30
キーと値のペアには .items()、キーだけには .keys()、値だけには .values() を使用します。
修正4 — ループ内でのアンパック
リストの各要素には3つのフィールドがありますが、2つしかアンパックしていません。Pythonはどのフィールドを省略するかを推測できません:
# データは1行に3フィールド
records = [
("alice", "alice@example.com", "admin"),
("bob", "bob@example.com", "user"),
]
# エラーになるコード — 3つの値に対して2つの変数しかない
for name, email in records: # ValueError
print(name, email)
# 修正済み — 3つ目の変数を追加
for name, email, role in records:
print(name, email, role)
# 修正済み — roleが不要な場合はスターを使用
for name, email, *_ in records:
print(name, email)
修正5 — 関数の戻り値のアンパック
戻り値は変化します。かつて2つの値を返していた関数に、後からタイムスタンプ、ステータスコード、リフレッシュレートなど3つ目のフィールドが追加されることがあります。ちょうど2つの変数にアンパックしている全ての呼び出し元は、実行時まで気づかずに壊れてしまいます:
def get_dimensions():
return 1920, 1080, 144 # リフレッシュレートは後から追加
# エラーになるコード
width, height = get_dimensions() # ValueError
# 修正済み
width, height, refresh = get_dimensions()
# 余分な値が本当に不要な場合
width, height, *_ = get_dimensions()
その関数を管理している場合、戻り値の追加は破壊的変更として扱います。ドキュメント化してください。呼び出し元は知る必要があります。
修正6 — CSVファイルの解析
CSVファイルは特にこの問題が起きやすいです。末尾のカンマ、オプションフィールド、スキーマの変更 — これら全てが予想より多くのカラムを持つ行を生成します:
import csv
# 行が2列以上ある場合にエラーになるコード
with open("data.csv") as f:
reader = csv.reader(f)
for row in reader:
name, score = row # 余分なカラムがある行でValueError
# 修正済み — 代わりに行のインデックスを使用
with open("data.csv") as f:
reader = csv.reader(f)
for row in reader:
name = row[0]
score = row[1]
# より良い方法 — 名前付きカラムにはDictReaderを使用
with open("data.csv") as f:
reader = csv.DictReader(f)
for row in reader:
print(row["name"], row["score"])
修正が機能したことを確認する方法
次の実行でValueErrorが発生しなければ、それが確認です。API、ファイル、データベースなどの外部データソースの場合、アンパックロジックを書く前に生のサンプルを出力してください:
# アンパックを決める前に形状を確認
data = some_function()
print(type(data), len(data), data)
# 確認後、自信を持ってアンパック
a, b, c = data
最初のprint文1つで、後の10分のデバッグを節約できます。
クイック診断チェックリスト
- 値と変数の数を数える — 一致する必要があります。または
*restを使用 - 辞書をイテレートしている? キーと値のペアを取得するために
.items()を追加 - ループアンパック
for a, b in list? まず各要素の実際の長さを確認 - CSVやJSONを解析している? カラムが変更された可能性があります — アンパック前に生の行を出力
- タプルを返す関数を呼び出している? 戻り値の数が増えていないか確認

