Python – Hoe op te lossen “ValueError: niet genoeg waarden om uit te pakken (verwacht 2, kreeg 1)”

Ik moet een functie schrijven add_to_dict(d, key_value_pairs)die elk gegeven sleutel/waarde-paar toevoegt aan een python-woordenboek. Het argument key_value_pairsis een lijst met tuples in de vorm (key, value).

De functie zou een lijst moeten retourneren van alle sleutel/waarde-paren die zijn gewijzigd (met hun oorspronkelijke waarden).

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

Ik krijg steeds een foutmelding

ValueError: niet genoeg waarden om uit te pakken (verwacht 2, kreeg 1)

Hoe los ik deze fout op?


Antwoord 1, autoriteit 100%

Hoe u uw code moet debuggen

'''
@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

Blijf het resterende deel lezen als u wilt weten hoe u een dict-object op de juiste manier kunt doorkruisen.


Verschillende manieren om een dictobject te doorkruisen

Python 3.x

De volgende segmenten laten zien hoe je een dictin Python 3.xdoorkruist.

Herhaal de set sleutels

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)

Herhaal de set sleutel-waarde-paren

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

Herhaal de reeks waarden

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

Python 2.x

De volgende segmenten laten zien hoe je een dictin Python 2.xdoorkruist.

Herhaal de set sleutels

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

keys()retourneert een lijstvan de sleutelset van het woordenboek d

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

iterkeys()retourneert een iteratorvan de sleutelset van woordenboek d

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

Herhaal de set sleutel-waarde-paren

values()retourneert een lijstvan de set sleutel-waarde-paar van woordenboek d

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

itervalues()retourneert een iteratorvan de set sleutel-waarde-paar van woordenboek d

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

Herhaal de reeks waarden

values()retourneert een lijst van de waardenset van woordenboek d

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

itervalues()retourneert een iterator van de waardenset van woordenboek d

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

Referentie:


Antwoord 2, autoriteit 53%

gebruik items()om op te lossen, zoals:

d = {"foo": "bar"}
for key, value in d.items():
    print key, value

Antwoord 3, autoriteit 5%

Je kunt deze fout vermijden als je het dictaat (van 1 miljoen inzendingen) niet herhaalt, maar alleen de lijst met mogelijkewijzigingen en kijkt of het iets in het dictaat verandert:

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

Uitvoer:

[] # 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

Je zou ook wat validatie in je parameters kunnen gooien – als een parameter fout is, wordt er niets uitgevoerd en ontstaat er een spreekfout:

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

Dus je krijgt duidelijkere foutmeldingen:

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

Other episodes