Python ValueError: too many values to unpack

Python

Python Problem Overview


I am getting that exception from this code:

class Transaction:
    def __init__ (self):
        self.materials = {}
    
    def add_material (self, m):
        self.materials[m.type + m.purity] = m
    
    def serialize (self):
        ser_str = 'transaction_start\n'
        
        for k, m in self.materials:
            ser_str += m.serialize ()
        
        sert += 'transaction_end\n'
        return ser_str

The for line is the one throwing the exception. The ms are Material objects. Anybody have any ideas why?

Python Solutions


Solution 1 - Python

self.materials is a dict and by default you are iterating over just the keys (which are strings).

Since self.materials has more than two keys*, they can't be unpacked into the tuple "k, m", hence the ValueError exception is raised.

In Python 2.x, to iterate over the keys and the values (the tuple "k, m"), we use self.materials.iteritems().

However, since you're throwing the key away anyway, you may as well simply iterate over the dictionary's values:

for m in self.materials.itervalues():

In Python 3.x, prefer dict.values() (which returns a dictionary view object):

for m in self.materials.values():

Solution 2 - Python

for k, m in self.materials.items():

example:

miles_dict = {'Monday':1, 'Tuesday':2.3, 'Wednesday':3.5, 'Thursday':0.9}
for k, v in miles_dict.items():
    print("%s: %s" % (k, v))

Solution 3 - Python

Iterating over a dictionary object itself actually gives you an iterator over its keys. Python is trying to unpack keys, which you get from m.type + m.purity into (m, k).

My crystal ball says m.type and m.purity are both strings, so your keys are also strings. Strings are iterable, so they can be unpacked; but iterating over the string gives you an iterator over its characters. So whenever m.type + m.purity is more than two characters long, you have too many values to unpack. (And whenever it's shorter, you have too few values to unpack.)

To fix this, you can iterate explicitly over the items of the dict, which are the (key, value) pairs that you seem to be expecting. But if you only want the values, then just use the values.

(In 2.x, itervalues, iterkeys, and iteritems are typically a better idea; the non-iter versions create a new list object containing the values/keys/items. For large dictionaries and trivial tasks within the iteration, this can be a lot slower than the iter versions which just set up an iterator.)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNikView Question on Stackoverflow
Solution 1 - PythonJohnsywebView Answer on Stackoverflow
Solution 2 - PythonSunhwan JoView Answer on Stackoverflow
Solution 3 - PythonKarl Knechtel - away from homeView Answer on Stackoverflow