Today, I noticed that not True 5
is syntactically valid but 5 not True
isn't.
The syntax error points to the first character of not, as if the operator couldn't be used here. However, 5 (not True)
works, which leads me to believe it is a parser issue.
Are there any reasons for this error?
- Is it a design decision taken by the language?
- Is it is a parser error, or a behaviour not defined by the language's rules?
I couldn't find any resources concerning this case.
CodePudding user response:
It's an operator precedence issue; see e.g. this table in the documentation.
binds more tightly than not
, so this:
not True 5
Is equivalent to:
not (True 5)
And True
evaluates as 1
in this case (so you get True 5 == 6
, and not 6 == False
). On the other hand:
5 not True
Is:
(5 not) True
Which doesn't make any sense. You would need to explicitly write:
5 (not True)
(Which would equal 5
, since not True
is False
and False
evaluates to 0
.)
CodePudding user response:
We need to look at the Python grammar to see why not True 5
is syntactically (though not semantically) valid while 5 not True
is a parse error. Here are the most relevant portions:
Relevant grammar rules
inversion:
| 'not' inversion
| comparison
comparison:
| bitwise_or
bitwise_or:
| bitwise_xor
bitwise_xor:
| bitwise_and
bitwise_and:
| shift_expr
shift_expr:
| sum
sum:
| sum ' ' term
| term
The order of these rules matches precedence of the various operators involved, from lowest precedence to highest. 'not' inversion
is listed before sum ' ' term
because the not
operator has lower precedence than
.
not <expr>
is parsed as an inversion. Reading top-down following the chain of derivations, you can see that an inversion could be a sum. This means that not True 5
can be parsed as the not
operator followed by an operand of True 5
.
Parse tree for not True 5
inversion
│ │
'not' inversion
│
comparison
│
bitwise_or
│
bitwise_xor
│
bitwise_and
│
shift_expr
│
sum
│
sum ' ' term
│ │
term '5'
│
'True'
On the other hand if you have 5 not True
there is no way to construct a parse tree. If you tried, 5 not True
would be parsed as sum ' ' term
. The left side is fine: 5
can be parsed as a sum. There's no valid parse for the right side, though: not True
is not a term.
Failed parse tree for 5 not True
sum ─┬────┐
│ │ │
sum ' ' term
│ │
term <error: no derivation for 'not' 'True'>
│
'5'
NB: The only way to work back "up" the grammar is to add parentheses. not True
is not a term, but (not True)
with parentheses is. 5 (not True)
is syntactically valid. Of course, it's still semantically invalid. But hey, if you don't care about semantics the parser won't stop you.