Search code examples
pythonsyntaxtupleslist-comprehension

Is this tuple syntax inside a Python list-comprehension? If not, what is it?


I am having some trouble understanding parts of syntax. Particularly when parentheses () are required for tuples.

For instance, this piece of code below:

c = {'a':10,'b':1,'c':22,'d':10}

tup = a,b = 4,5

print(a)
print(b)
print(tup)

newlist = [(x,y) for y,x in c.items()]

print(newlist)

The output for this code is:

4
5
(4, 5)
[(10, 'a'), (1, 'b'), (22, 'c'), (10, 'd')]

When trying to take the parentheses out of x, y in the list comprehension statement, I get a traceback. However, every other tuple in this code does not require parenthesis.

What am I missing? Why is it that Python understands a,b to be a tuple but not x,y when it is in a list comprehension statement?

It seems to me that Python is inconsistent with tuple syntax. I tried taking the parentheses out and putting them back to understand how the syntax works.


Solution

  • Parentheses are needed to give priority to operators. Consider the two following lines of code, which differ only by the parentheses:

    tup_a = 3, 4 + 10, 20
    tup_b = (3, 4) + (10, 20)
    

    The first line defines a tuple tup_a of 3 elements, (3, 14, 20). The second line defines two tuples (3, 4) and (10, 20), then concatenates them into a tuple of four elements, (3, 4, 10, 20).

    Wrong parentheses can easily result in an error:

    tup_c = 3, 4 * 10, 20
    tup_d = (3, 4) * (10, 20)
    

    The first line defines a tuple of 3 elements, (3, 40, 20). The second line results in a TypeError because it defines two tuples (3, 4) and (10, 20) and then attempts to multiply them, but the multiplication operator * doesn't know what to do with tuples.

    You encountered a similar issue. Consider the following lines of codes:

    x = 42
    c = {'a': 10, 'b': 1, 'c': 22, 'd': 10}
    
    l_a = [(x, y) for y,x in c.items()]  # [(10, 'a'), (1, 'b'), (22, 'c'), (10, 'd')]
    l_b = [x, (y for y,x in c.items())]  # [42, <generator object>]
    l_c = [x, y for y,x in c.items()]    # SyntaxError: invalid syntax
    

    This code correctly defines two lists l_a and l_b, but then it raises a SyntaxError when trying to define l_c.

    The designers of python decided that the syntax for l_c was ambiguous, and you should add parentheses to explicitly specify whether you meant the same thing as l_a or as l_b.

    Note that the line of code for l_b would raise a NameError: name 'x' is not defined if I hadn't added x = 42 at the beginning, since the role of x is not the same in l_b as it is in l_a.