Python – Too many values to unpack (expected 4)

linelistpython

I have this piece of basic code just trying to split a file into 4 lists. The .txt file is formatted as shown underneath the code, with spaces delimiting each number. The error appearing is 'ValueError: too many values to unpack (expected 4)'.

file = open("myfreefall.txt","r")
for line in file:
     if not line.startswith('#'):
         v,a,t,y= line.split(' ')


#v  a  t  y
-0.10 -9.81 0.01 5500.00
-0.20 -9.81 0.02 5500.00
-0.29 -9.81 0.03 5500.00
-0.39 -9.81 0.04 5499.99
-0.49 -9.81 0.05 5499.99
-0.59 -9.81 0.06 5499.99
-0.69 -9.81 0.07 5499.98
-0.78 -9.81 0.08 5499.97
...

However I changed the code to be as shown below to test how many variables it was expecting, and the error changed to 'not enough values to unpack (expected 5, got 4)'. This doesn't make sense as now the code is unpacking the four variables I wanted! Any solutions/pointers would be much appreciated.

file = open("myfreefall.txt","r")
for line in file:
     if not line.startswith('#'):
         v,a,t,y,test= line.split(' ')

Best Answer

As commenters have suggested, try printing the line to see the line that's actually causing a problem (but be sure to insert the print before the line.split).

The most likely problem is a blank line at the end, which is read as a newline character. If so the easiest solution is probably to tack on another condition to the if statement:

file = open("myfreefall.txt","r")
for line in file:
     if not line.startswith('#') and line != '\n':
     # or, more robust:
     if not line.startswith('#') and len(line) == 4:
         v,a,t,y= line.split(' ')

Or with a try/except:

file = open("myfreefall.txt","r")
for line in file:
    try:
       v,a,t,y= line.split(' ')
    except ValueError:
       continue
       # Skip over this line if the extraction fails

The second if-statement is more robust because it will only try to extract your four variables if there are exactly four list entries to work with. Any other case (more or fewer entries to extract from) will be ignored. You can tailor it a bit more to your needs, e.g. by changing it to 'len(line) >= 4' if you wanted to allow longer lines to be read as well.

To be honest, I can't think of a particular advantage for the try/except variant, but since I just wrote it out I might as well leave it in. It might be a bit too robust, in fact, because it would also skip lines that cause ValueErrors for reasons other than there being too few entries to work with.

Your second attempt failing as you describe makes perfect sense. You're telling python to split a list of four entries into five variables, v, a, t, y and test. That's what the error is referring to when it says, 'expected 5, got 4'. The behaviour of your error probably changed because the code fails a lot sooner now. Before it was working for all lines except the last one, where there's only one list entry to use. With your change to five variables it's causing an error with the very first line, where there are four entries but now you're asking for five.