Search code examples
pythonpython-3.xiterable-unpacking

Why comma separated iterables in for doesn't work like zip?


What I want to understand is why does the following code

for x, y in [1,2], [3,4]:
    print(x, y, x + y)

prints

1 2 3
3 4 7

instead of

1 3 4
2 4 6

Now, I know zip does this work and not using zip to iterate over a pair of lists could be considered an anti-pattern, but I still need an explanation for this default behavior.

From my point of view, the code above should intuitively work just like the builtin zip function

for (x, y) in zip([1,2], [3,4]):
    print(x, y, x + y)

which prints

1 3 4
2 4 6

From memory I remember seeing the explanation for this technique a long time ago (and I guess that's why this solution comes to mind first), but I've done searches now, including on the whole section 5 of Python 3 documentation but I couldn't find any explanations for this behavior, not even on section 5.6. (Looping Techniques).

Is this a 4th Gotcha?


Solution

  • I think this is the expected behavior!
    Consider that [1,2], [3,4] is a tuple literal, equivalent to the tuple ([1,2], [3,4]). (You might be using this without even noticing, for instance when assigning multiple values with a, b, c = 10, 20, 30 disregarding the ()...).

    So in your example, the loop iterates through this list as follows:

    # First iteration we get:
    x, y = [1, 2]  
    # Which is the same as:
    x = 1
    y = 2
    # Which would print:
    print(x, y, x+y)
    >> 1, 2, 3
    
    # Second iteration we get:
    x, y = [3, 4]  
    # Which is the same as:
    x = 3
    y = 4
    # Which would print:
    print(x, y, x+y)
    >> 3, 4, 7  
    

    Does that make more sense now?


    Considering zip: If zip would do the same thing, then I'd be suspicious! How is there this very common and considered-useful but completely redundant thing lying around? Hasn't anyone noticed? So you shouldn't expect them to do the same! ;-)


    Edit due to a request for a pointer to documentation.
    From 5.3 Tuples and Sequences:

    A tuple consists of a number of values separated by commas, for instance: ...
    As you see, on output tuples are always enclosed in parentheses, so that nested tuples are interpreted correctly; they may be input with or without surrounding parentheses, although often parentheses are necessary anyway (if the tuple is part of a larger expression).