I just started learning Python and while I was playing with Tuples I noticed that the ValueError output differs if you provide less than the exact number of elements in the tuple. For example:
>>> tuple = (1, 2, 3)
>>> (a, b) = tuple
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>> (a, b, c, d) = tuple
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 4, got 3)
My question is:
Why in case of too many values to unpack error, the output doesn’t show how many elements in the tuple are there?
I peeked into CPython code on GitHub but I don’t understand code well enough yet.
It doesn’t have to be a tuple on the right hand side. It can also be a iterator:
def foo():
for i in range(1_000_000):
yield i
it = foo()
x, y = it
After x and y got assigned a value, it would still not completely exhausted but at that point it is clear that it has more than 2 elements. No need to continue iterating until 1_000_000.
It is also clear if you check the next value in it:
You didn’t mention which version of Python you’re using (noting version and platform are always a good idea when asking a question), but I suspect it might be a bit older than current GitHub source. If you scroll down to line 2238, notice that the current code does indicate the size of the time to be unpacked. I just checked, and see that 3.13 behaves as you saw, while the yet-to-be-released 3.14 includes the tuple size in its error message. (This only applies to dicts, lists and tuples, no even subclasses of them.) That code was updated 2024-09-10.
Oh, such a cool feature! In the case of unpacking the iterator, it is impossible to know how many elements it will return before executing it and getting to the end - as far as I understand… Thanks for sharing this!
Oh, I forgot to mention the version. You’re right, it is older than the GitHub source, I was using Python 3.10.11 on intel macbook.
If you scroll down to line 2238, notice that the current code does indicate the size of the time to be unpacked.
I saw line 2234, where the size isn’t indicated, so I thought this was what I was getting in the output - but I guess this output is only in case of other data types other than lists, dicts and tuples.
I also just checked the code for the version I was using it doesn’t have that additional if:
>>> from __future__ import patience
>>> import itertools
>>> (a, b) = itertools.count()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
(still counting...)
(wait for it...)
(wait for it...)
(wait for it...)
(wait for it...)