HOWTO · Python
ValueError: Python でアンパックするのに十分な値がありません
Python の `ValueError: not enough values to unpack` は、辞書のキーを反復処理しながら値にもアクセスする、入力ステートメントで 2 つの入力を求めながら 2 つ未満の値しか提供しない、期待される個数より少ない値を代入する、といったさまざまなシナリオで発生します。いずれの場合も、期待する個数より少ない値を代入しようとしたことがこのエラーの原因です。
このページの内容
Python は、代入やループヘッダーで、右辺のイテラブルが供給できる数より多くの変数を要求すると、ValueError: not enough values to unpack を発生させます。直接の代入、分割後のフィールド数が足りない入力、各ペアを誤った数の名前にアンパックする辞書ループで、このエラーに遭遇します。このガイドでは、メッセージの読み方とそれぞれの状況の修正方法を説明します。
Python が ValueError: not enough values to unpack を発生させる理由
アンパックは、イテラブル(タプル、リスト、文字列、ビューオブジェクトなど)の要素を、対応する名前のリストに割り当てる操作です。a, b, c = 3, 5 では、Python は何も代入する前に両辺の数を数えます。左辺には 3 つの名前、右辺には 2 つの値があります。書かれたターゲットの数より少ない値しか届かなかったため、インタープリターは ValueError を発生させ、そのメッセージには両方の数 expected 3, got 2 が示されます。この 2 つの数字が診断の手がかりです。最初の数字は書いたターゲットの数、2 番目はイテラブルが実際に生成した値の数です。
次の例を実行して、Python が報告するメッセージを確認してください(コードと出力内の文字列は英語のまま表示されます):
try:
a, b, c = 3, 5
except ValueError as error:
print("ValueError:", error)
ValueError: not enough values to unpack (expected 3, got 2)
try/except がなければ、プログラムは代入行で停止します。同じ不一致は、ターゲットリストより短いあらゆるイテラブルで発生します。a, b, d, e = [1, 2, 3] は 3 つの要素を持つリストから 4 つの名前を要求し、a, b, c = 2 は 1 つの整数から 3 つの名前を要求しますが、Python はこれをまったくアンパックできません。
代入と入力でのアンパックエラーを修正する
最も簡単な修正は、両辺を一致させることです。左辺の名前の数は、右辺が供給できる値の数と一致する必要があります。値が input() から来る場合、input() は常に文字列を返すことを忘れないでください。そのため、代入が実際に受け取るフィールドの数は split() が決めます。次のプログラムはカンマ区切りの 3 つの数値を要求し、3 つを受け取るため、アンパックが成功して乗算が実行されます(プロンプトや出力の文字列は英語のまま表示されます)。次の例を実行してください:
import sys
from io import StringIO
# Simulate typing "2,2,2" at the prompt.
sys.stdin = StringIO("2,2,2\n")
x, y, z = input("Enter three numbers to multiply: ").split(",")
product = int(x) * int(y) * int(z)
print("The product of x, y, and z is:", product)
Enter three numbers to multiply: The product of x, y, and z is: 8
sys.stdin の行は、ユーザーが 2,2,2 とタイプする代わりをしています。実際のプログラムでは input() を通常どおり呼び出し、キーボードの前にいる人が届くフィールドの数を決めます。ターゲットが必要とする数より少ないフィールドが入力されると、分割されたリストが短すぎて、同じ ValueError が現れます:
import sys
from io import StringIO
# Simulate typing "1,2" at the prompt.
sys.stdin = StringIO("1,2\n")
try:
x, y, z = input("Enter values for x, y and z: ").split(",")
except ValueError as error:
print("ValueError:", error)
Enter values for x, y and z: ValueError: not enough values to unpack (expected 3, got 2)
右辺の長さが正当に変化し得る場合、スター付きターゲットが余分な要素を吸収します。first, *rest = [1, 2, 3] は first に 1 を、rest に [2, 3] を束縛します。スターが役立つのは余分な要素が問題の場合だけです。届く値が少なすぎる場合は、数を一致させるか、先に入力を検証してください。
.items() で辞書のアンパックを修正する
辞書はキーと値のペアを格納します。辞書そのものを反復処理するとキーだけが得られますが、.items() は (key, value) ペアのビューを返し、各ペアは正確に 2 つの値を保持します。3 つの標準的なビューを確認できます(コードと出力内のラベルは英語のままです):
student = {"name": "Zeeshan Afridi", "degree": "BSSE", "section": "A"}
print("Keys:", student.keys())
print("Values:", student.values())
print("Items:", student.items())
Keys: dict_keys(['name', 'degree', 'section'])
Values: dict_values(['Zeeshan Afridi', 'BSSE', 'A'])
Items: dict_items([('name', 'Zeeshan Afridi'), ('degree', 'BSSE'), ('section', 'A')])
.items() から得られる各要素は 2 つの値を持つペアなので、3 つのターゲットを持つループヘッダーは最初の反復で失敗します。個数を決めるのはメソッドではなく、値を供給するペアのほうです:
student = {"name": "Zeeshan Afridi", "degree": "BSSE", "section": "A"}
try:
for k, v, l in student.items():
print(k, v, l)
except ValueError as error:
print("ValueError:", error)
ValueError: not enough values to unpack (expected 3, got 2)
修正方法は、各ペアを 2 つの名前にアンパックすることです。1 つはキー用、もう 1 つは値用です:
student = {"name": "Zeeshan Afridi", "degree": "BSSE", "section": "A"}
for key, value in student.items():
print("Key:", key)
print("Value:", value)
Key: name
Value: Zeeshan Afridi
Key: degree
Value: BSSE
Key: section
Value: A
キーだけが必要な場合は、for key in student: のように辞書を直接反復処理します。値だけが必要な場合は .values() を使います。素のキーループをアンパックしないよう注意してください。for k, v in student: は各キー文字列自体をアンパックしようとするため、複数文字のキーでは too many values to unpack で失敗します。
入力を検証してアンパックエラーを処理する
2 つの習慣でこのエラーをユーザーから遠ざけられます。まず、アンパック前にフィールドを数えます。split() はリストを返し、len() で割り当てる予定の名前の数と一致するかを確認できるため、明確なプロンプトでデータを再入力してもらえます(コードと出力内の文字列は英語のまま表示されます):
import sys
from io import StringIO
# Simulate typing "1,2" at the prompt.
sys.stdin = StringIO("1,2\n")
parts = input("Enter three numbers to multiply: ").split(",")
if len(parts) != 3:
print("Please enter exactly three numbers separated by commas.")
else:
x, y, z = (int(part) for part in parts)
print("The product of x, y, and z is:", x * y * z)
Enter three numbers to multiply: Please enter exactly three numbers separated by commas.
次に、アンパックと変換のブロックを try/except で囲みます。Python のキーワードは try と except であり、他の言語で使われる try-catch という表記ではありません。int() も数値でないフィールドに対して ValueError を発生させるため、1 つの except 節で短いフィールドリストと変換できない値の両方をカバーできます:
import sys
from io import StringIO
# Simulate typing "2,two,4" at the prompt.
sys.stdin = StringIO("2,two,4\n")
try:
x, y, z = input("Enter three numbers to multiply: ").split(",")
product = int(x) * int(y) * int(z)
print("The product of x, y, and z is:", product)
except ValueError as error:
print("Could not use that input:", error)
Enter three numbers to multiply: Could not use that input: invalid literal for int() with base 10: 'two'
例外をキャッチすればプログラムは回復できますが、データ自体は修正されません。長さのチェック(必要に応じて数値や形式のチェックも)を優先し、ユーザーに何を入力すべきかを正確に伝えられるようにして、try/except はアンパック自体の安全網としておきましょう。