When are parentheses required around a tuple?
Asked Answered
M

3

60

Is there a reference somewhere defining precisely when enclosing tuples with parentheses is or is not required?

Here is an example that surprised me recently:

>>> d = {}
>>> d[0,] = 'potato'
>>> if 0, in d:
  File "<stdin>", line 1
    if 0, in d:
        ^
SyntaxError: invalid syntax
Marketa answered 15/4, 2013 at 14:31 Comment(4)
I find it especially interesting that for k, in d: print k does work in that case.Notarial
The Python grammar will show you what is allowed, for example, in an if statement. You'd have to read over the full grammar to figure out where unparenthesized tuples are accepted, which is why I'm not posting this as an answer.Exceed
...I fail to understand how you could have been surprised by the for failing with 0,... python identifiers must start with a (unicode)letter or underscore and 0 is not a valid python identifier hence I would have expected a SyntaxError there.Honig
That's why David said for k, not for 0, (It works i.e. it successfully does tuple unpacking into k for the case where the dict keys are 1-element tuples)Marketa
S
57

The combining of expressions to create a tuple using the comma token is termed an expression_list. The rules of operator precedence do not cover expression lists; this is because expression lists are not themselves expressions; they become expressions when enclosed in parentheses.

So, an unenclosed expression_list is allowed anywhere in Python that it is specifically allowed by the language grammar, but not where an expression as such is required.

For example, the grammar of the if statement is as follows:

if_stmt ::=  "if" expression ":" suite
             ( "elif" expression ":" suite )*
             ["else" ":" suite]

Because the production expression is referenced, unenclosed expression_lists are not allowed as the subject of the if statement. However, the for statement accepts an expression_list:

for_stmt ::=  "for" target_list "in" expression_list ":" suite
              ["else" ":" suite]

So the following is allowed:

for x in 1, 2, 3:
    print(x)
Surveying answered 15/4, 2013 at 14:40 Comment(3)
+1 That certainly explains why for k, in d works (because for k, v in d works).Notarial
Question: Should you write it for x in 1, 2, 3: or for x in (1, 2, 3):? I've always written it the second way, but that was because I didn't know the first way was valid until just now when I tried. Now I'm wondering if the () are unnecessary noise, or if they somehow help in reading the code. Does PEP8 provide any guidance on this?Utimer
@Utimer there's no specific guidance in PEP8. It might help to compare with if statements, where parentheses are recommended only for a condition that spans multiple lines. So: for x in (1, <newline> 2, <newline> 3):.Surveying
U
20

Anywhere you are allowed to use the expression_list term, you do not need to use parenthesis.

The if statement requires an expression, and does not support an expression_list.

Examples of syntax that does allow expression_list:

Grepping the Expressions, Simple and Compound statements documentation for expression_list will tell you all locations that expression_list is used in the Python grammar.

Unnerve answered 15/4, 2013 at 14:41 Comment(7)
Oh yeah? How about 1,2,3 + 4,5? It doesn't result in the expression list you might expect...Derosier
@Derosier what has that got to do with my answer? What outcome did you expect?Unnerve
Because 1,2,3 + 4,5 results in the expression 1,2,7,5, which is not what a casual reader would expect, and comes from overloading + for sequence append.Derosier
@Derosier sorry, but 1, 2, 7, 5 is exactly what I'd expect. Each part between commas is an expression; the whole is an expression_list. There is no grammar rule that sums expression lists; instead + is part of one of the contained expressions (3 + 4). To add up two tuples, make two separate expressions by adding parentheses.Unnerve
Yes I know that. However, non-Python users or people who missed the lack of trailing comma would expect a concatenated tuple 1,2,3, + 4,5, . What a difference the trailing comma makes.Derosier
@smci: By adding in a comma you turned the expression to +4, which is just 4. You are still not concatenating two tuples, you are defining one tuple with the +4 producing 4.Unnerve
Martijn I knew that when I posted it; I intentionally posted it to make the point that there can be cases of (in this case, visual) ambiguity, and in that case parenthesizing is highly recommended. I wasn't asking you to explain it, just making the point that ambiguity can exist.Derosier
D
3

Parentheses are also (semantically) required when you want to avoid ambiguity.

The following are two different expressions... just because something is an 'expression list', doesn't result in the expression list you might expect :)

(1, 2, 3) + (4, 5) # results in (1, 2, 3, 4, 5) because + does sequence.extend on the tuples
1, 2, 3 + 4, 5     # this results in (1, 2, 7, 5) because + adds the elements, since there were no parentheses to protect the separate tuples
Derosier answered 22/11, 2016 at 19:12 Comment(2)
Same as 1+2+3 * 4+5. The result is perfectly clear when you know the operator precedence in Python. Using additional parentheses is not necessary here but helps those new in Python (or in math).Graves
@Jeyekomon: No, you're missing the point: Python operator precedence differs from C/C++ operator precedence which differs from Java operator precedence etc. These ambiguities can and do cause even an extremely experienced programmer to make mistakes. Python does not exist in a vacuum. Every week on SO you can see such posts by (experienced) programmer proving this.Derosier

© 2022 - 2024 — McMap. All rights reserved.