This is a bit of a (very basic) language-lawyer kind of question. I understand what the code does, and why, so please no elementary explanations.
In an expression, in
has higher precedence than and
. So if I write
if n in "seq1" and "something":
...
it is interpreted just like
if (n in "seq1") and "something":
...
However, the in
of a for
loop has lower precedence than and
(in fact it has to, otherwise the following would be a syntax error). Hence if a Python beginner writes
for n in "seq1" and "something":
...
..., it is equivalent to this:
for n in ("seq1" and "something"):
...
(which, provided "seq1" is truthy, evaluates to for n in "something"
).
So, the question: Where is the precedence of the for-loop's in
keyword specified/documented? I understand that n in ...
is not an expression in this context (it does not have a value), but is part of the for
statement's syntax. Still, I'm not sure how/where non-expression precedence is specified.
In the context of a for
statement, the in
is just part of the grammar that makes up that compound statement, and so it is distinct from the operator in
. The Python grammar specification defines a for
statement like this:
for_stmt ::= "for" target_list "in" expression_list ":" suite
["else" ":" suite]
The point to make is that this particular in
will not be interpreted as part of target_list, because a comparison operation (e.g. x in [x]
) is not a valid target. Referring to the grammar specification again, target_list and target are defined as follows:
target_list ::= target ("," target)* [","]
target ::= identifier
| "(" target_list ")"
| "[" target_list "]"
| attributeref
| subscription
| slicing
| "*" target
So the grammar ensures that the parser sees the first in
token after a target_list as part of the for ... in ...
statement, and not as a binary operator. This is why trying to write things very strange like for (x in [x]) in range(5):
will raise a syntax error: Python's grammar does not permit comparisons like (x in [x])
to be targets.
Therefore for a statement such as for n in "seq1" and "something"
is unambiguous. The target_list part is the identifier n
and the expression_list part is the iterable that "seq1" and "something"
evaluates to. As the linked documentation goes on to say, each item from the iterable is assigned to target_list in turn.