Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - How to fix “ValueError: not enough values to unpack (expected 2, got 1)” [closed]

I need to write a function add_to_dict(d, key_value_pairs) which adds each given key/value pair to a python dictionary. The argument key_value_pairs will be a list of tuples in the form (key, value).

The function should return a list of all of the key/value pairs which have changed (with their original values).

def add_to_dict(d, key_value_pairs):

   newlist = []

   for key,value in d:
       for x,y in key_value_pairs:
           if x == key:
              newlist.append(x,y)
            
   return newlist

I keep getting an error

ValueError: not enough values to unpack (expected 2, got 1)

How do I solve this error?

like image 224
Hamish Avatar asked Aug 31 '18 05:08

Hamish


People also ask

How do I fix ValueError is not enough values to unpack in python?

The “ValueError: not enough values to unpack” error is raised when you try to unpack more values from an iterable object than those that exist. To fix this error, make sure the number of values you unpack from an iterable is equal to the number of values in that iterable.

How do I fix ValueError too many values to unpack expected 2?

The Python "ValueError: too many values to unpack (expected 2) in Python" occurs when the number of variables in the assignment is not the same as the number of values in the iterable. To solve the error, declare exactly as many variables as there are items in the iterable.

What does ValueError too many values to unpack expected 2 mean in python?

This error occurs when the number of variables doesn't match the number of values. As a result of the inequality, Python doesn't know which values to assign to which variables, causing us to get the error ValueError: too many values to unpack .


3 Answers

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 can't 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 don't know if you want to update the key-value-pair in the dictionary `d`
        # take out the following line if you don't 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:

  • What is the difference between list and iterator in Python?
like image 90
KaiserKatze Avatar answered Nov 01 '22 16:11

KaiserKatze


use items() to resolve, like:

d = {"foo": "bar"}

for key, value in d.items():
    print key, value
like image 37
pfctgeorge Avatar answered Nov 01 '22 16:11

pfctgeorge


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 won't 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 won't 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
like image 2
Patrick Artner Avatar answered Nov 01 '22 15:11

Patrick Artner