dictionary – Python – How to fix “ValueError: not enough values to unpack (expected 2, got 1)”

dictionary – Python – How to fix “ValueError: not enough values to unpack (expected 2, got 1)”

How you should debug your code


@param d: a dictionary
@param key_value_pairs: a list of tuples in the form `(key, value)`
@return: a list of tuples of key-value-pair updated in the original dictionary

def add_to_dict(d, key_value_pairs):

    newlist = []

    for pair in key_value_pairs:

        # As is mentioned by Mr Patrick
        # you might not want to unpack the key-value-pair instantly
        # to avoid possible corrupted data input from
        # argument `key_value_pairs`
        # if you cant guarantee its integrity
        try:
            x, y = pair
        except (ValueError):
            # unable to unpack tuple
            tuple_length = len(pair)
            raise RuntimeError(Invalid argument `key_value_pairs`!
                Corrupted key-value-pair has ({}) length!.format(tuple_length))

        # Instead of using nesting loop
        # using API would be much more preferable
        v = d.get(x)

        # Check if the key is already in the dictionary `d`
        if v:
            # You probably mean to append a tuple
            # as `array.append(x)` takes only one argument
            # @see: https://docs.python.org/3.7/library/array.html#array.array.append
            #
            # Besides, hereby I quote
            # The function should return a list of all of the key/value pairs which have changed (with their original values).
            # Thus instead of using the following line:
            #
            # newlist.append((x, y,))
            #
            # You might want a tuple of (key, old_value, new_value)
            # Hence:
            newlist.append((x, v, y,))

        # I dont know if you want to update the key-value-pair in the dictionary `d`
        # take out the following line if you dont want it
        d[x] = y

    return newlist

Please keep reading the remaining part if you want to know how to traverse a dict object properly.


Different ways to traverse a dict object

Python 3.x

The following segments demonstrate how to traverse a dict in Python 3.x.

Iterate the set of keys

for key in d:
    value = d[key]
    print(key, value)

the code segment above has the same effect as the following one:

for key in d.keys():
    value = d[key]
    print(key, value)

Iterate the set of key-value-pairs

for key, value in d.items():
    print(key, value)

Iterate the set of values

for value in d.values():
    print(value)

Python 2.x

The following segments demonstrate how to traverse a dict in Python 2.x.

Iterate the set of keys

for key in d:
    value = d[key]
    print(key, value)

keys() returns a list of the key set of dictionary d

for key in d.keys():
    value = d[key]
    print(key, value)

iterkeys() returns an iterator of the key set of dictionary d

for key in d.iterkeys():
    value = d[key]
    print(key, value)

Iterate the set of key-value-pairs

values() returns a list of the key-value-pair set of dictionary d

for key, value in d.items():
    print(key, value)

itervalues() returns an iterator of the key-value-pair set of dictionary d

for key, value in d.iteritems():
    print(key, value)

Iterate the set of values

values() returns a list of the value set of dictionary d

for value in d.values():
    print(value)

itervalues() returns a iterator of the value set of dictionary d

for value in d.itervalues():
    print(value)

Reference:

use items() to resolve, like:

d = {foo: bar}

for key, value in d.items():
    print key, value

dictionary – Python – How to fix “ValueError: not enough values to unpack (expected 2, got 1)”

You can avoid this error if you do not iterate over the dict (of 1 million entries) but only over the list of possible changes and see if it changes anything in the dict:

def add_to_dict(d, key_value_pairs):
    Adds all tuples from key_value_pairs as key:value to dict d, 
    returns list of tuples of keys that got changed as (key, old value)
    newlist = []


    for item in key_value_pairs:

        # this handles your possible unpacking errors
        # if your list contains bad data 
        try:
            key, value = item
        except (TypeError,ValueError):
            print(Unable to unpack {} into key,value.format(item))

        # create entry into dict if needed, else gets existing
        entry = d.setdefault(key,value) 

        # if we created it or it is unchanged this wont execute
        if entry != value:
            # add to list
            newlist.append( (key, entry) )
            # change value
            d[key] = value

    return newlist



d = {}
print(add_to_dict(d, (  (1,4), (2,5) ) ))    # ok, no change
print(add_to_dict(d, (  (1,4), (2,5), 3 ) )) # not ok, no changes
print(add_to_dict(d, (  (1,7), (2,5), 3 ) )) # not ok, 1 change

Output:

[] # ok

Unable to unpack 3 into key,value
[] # not ok, no change

Unable to unpack 3 into key,value
[(1, 4)] # not ok, 1 change

You could also throw in some validation onto your parameters – if any parameter is wrong, nothing will be executed and an speaking error arises:

import collections 

def add_to_dict(d, key_value_pairs):
    Adds all tuples from key_value_pairs as key:value to dict d, 
    returns list of tuples of keys that got changed as (key, old value)

    if not isinstance(d,dict):
        raise ValueError(The dictionary input to add_to_dict(dictionary,list of tuples)) is no dict)

    if not isinstance(key_value_pairs,collections.Iterable):
        raise ValueError(The list of tuples input to add_to_dict(dictionary,list of tuples)) is no list)  

    if len(key_value_pairs) > 0:
        if any(not isinstance(k,tuple) for k in key_value_pairs):
            raise ValueError(The list of tuples includes non tuple inputs)        

        if any(len(k) != 2 for k in key_value_pairs):
            raise ValueError(The list of tuples includes tuple != 2 elements)        

    newlist = []
    for item in key_value_pairs:            
        key, value = item

        # create entry into dict if needed, else gets existing
        entry = d.setdefault(key,value) 

        # if we created it or it is unchanged this wont execute
        if entry != value:
            # add to list
            newlist.append( (key, entry) )
            # change value
            d[key] = value

    return newlist

So you get clearer error messages:

add_to_dict({},tata) 
# The list of tuples input to add_to_dict(dictionary,list of tuples)) is no list

add_to_dict({},[tata])
# The list of tuples includes non tuple inputs

add_to_dict({},[ (1,2,3) ])
# The list of tuples includes tuple != 2 elements

add_to_dict({},[ (1,2) ])
# ok

Leave a Reply

Your email address will not be published. Required fields are marked *