Christina Zhou
Christina Zhou

Reputation: 1863

python iterating over multiple values in for loop

My for loop that has for value1, value2 in args is failing and I'm not sure why.

def school_completion(*args):
    """
    If any of the subjects have one or more incomplete testlet, the whole school is
    incomplete.

    :param args: tuple of 7 strs
        Should come as:
        (Eligible Students,
        ELA Required,
        ELA Completed,
        Math Required,
        Math Completed,
        Science Required,
        Science Completed)
    :return: str
    """
    # If there are no eligible students, return a dash.
    if args[0] == '0':
        return '-'

    # Set a boolean trigger.
    complete = True

    # Check for each subject pair.
    for required,completed in args[1:]:
        if required != completed:
            complete = False

    return 'Complete' if complete else 'Follow Up'

school_completion('1','6','6','7','7','8','8')

This gives me an error ValueError: not enough values to unpack (expected 2, got 1) that seems to occur at for required,completed in args[1:].

I also tried having my function take in (arg, *args) (thus avoiding any error with slicing the tuple). That also didn't work.

Upvotes: 4

Views: 308

Answers (2)

chuck
chuck

Reputation: 1447

args is a tuple. You can only iterate over a tuple one by one:

for el in args[1:]:
   # Do something...

You can iterate over multiple items only under ceratin circumstances, for example:

d = {'one': 1, 'two': 2}
for key, value in d.items():
    # Do something...

The items method of a dictionary returns a special dict_items object that can be iterated over like that. You can't just do it with anything, it doesn't even make sense for tuples.

If you want to get more specific, the behaviour of an object when it's being iterated over is determined by the iterator it returns in its __iter__ method, and what that iterator returns in its __next__ method. If it just returns a single value, like in a tuple, then you can't unpack it to several values. In the example above, dict__items returns a 2-item tuple when iterated over, and therefore can be unpacked.

Upvotes: 3

blhsing
blhsing

Reputation: 106618

Unpacking items in a sequence requires that each item in the sequence be an iterable that yields the same number of items that the expression receiving the values is expecting. You can instead use the zip function to pair the items in the sequence after slicing them by odd and even indices.

Change:

for required,completed in args[1:]:

to:

for required, completed in zip(args[1::2], args[2::2]):

Upvotes: 3

Related Questions