这是否是Python操作符层次结构的后果?
not(True) * True
# False
True * not(True)
# SyntaxError: invalid syntax
这是否是Python操作符层次结构的后果?
not(True) * True
# False
True * not(True)
# SyntaxError: invalid syntax
这是 Python 中运算符的层级顺序导致的后果吗?
是的(尽管通常术语是 运算符优先级)。简而言之:
not
isn't a function; it's an operator. Therefore, we don't need to write parentheses for not (True)
, and in fact they don't do anything here. All that happens is that the parentheses are treated as ordinary grouping parentheses - (True)
is evaluated before anything else, becoming True
. So, let's consider the examples without the parentheses.
not True * True
means not (True * True)
. It does not mean (not True) * True
, due to operator precedence. This is by design:
>>> not 1 * 0
True
>>> not (1 * 0)
True
>>> (not 1) * 0
0
It would, the developers figured, be unexpected to write something like not 1 * 0
and get an integer result, and unexpected to write not
in front of a mathematical operation and have the not
only apply to the first thing in that expression.
Because of that same operator precedence, True * not True
is a syntax error. Python parses the not
by itself as the right-hand side of the *
, because it hasn't yet worked out to put not True
together. True * not
is obviously nonsense. Or, another way of looking at it: "not
followed by an expression" isn't in the list of "things that can be an operand for *
".
This is perhaps surprising because the other commonly used unary operator, -
(i.e., unary negation), doesn't have this issue. But that's because the precedence is the other way around: unary negation is processed before multiplication, not after.
The same is true for and
and or
combinations:
>>> 3 * 5 and 1 # 3 * 5 is evaluated first
1
>>> 3 * (5 and 1)
3
>>> 3 or 1 * 5 # 1 * 5 is evaluated first, even though it comes later
3
>>> (3 or 1) * 5
15
a + b + c * d
中,你可以通过重载操作符看到,在求值时先计算 a + b
,再计算 c * d
。 - user2357112True * not True
的解析失败也不是因为它还没有机会应用 not True
。(not
后跟一个表达式"不在"可以成为"*"操作数的事物列表"的部分是正确的。) - user2357112这是一个优先级的问题,以及如何实现优先级。
*
的优先级比not
更高,在Python语法中的实现方式是,有一种表达式类型的层次结构,使得高优先级的运算符可以成为低优先级运算符的参数“根”,但反过来则不行。
例如,乘法表达式的文法规则为:
term[expr_ty]:
| a=term '*' b=factor { _PyAST_BinOp(a, Mult, b, EXTRA) }
| a=term '/' b=factor { _PyAST_BinOp(a, Div, b, EXTRA) }
| a=term '//' b=factor { _PyAST_BinOp(a, FloorDiv, b, EXTRA) }
| a=term '%' b=factor { _PyAST_BinOp(a, Mod, b, EXTRA) }
| a=term '@' b=factor { CHECK_VERSION(expr_ty, 5, "The '@' operator is", _PyAST_BinOp(a, MatMult, b, EXTRA)) }
| factor
term
是用于乘法表达式的语法规则。此规则中的前5个选项都由一个乘法优先级运算符位于中间,另一个term
位于运算符左侧,以及一个factor
位于右侧组成,其中factor
是下一个更高优先级运算符类别的规则。第6个选项只是一个factor
。
像这样构建语法规则可以确保解析出来的语法树始终与操作符优先级给出的结构相匹配,但也意味着低优先级的操作符不能成为高优先级操作符参数的“根”,即使表达式似乎不含歧义也无法这样做。没有语法规则能允许not
表达式作为*
表达式的参数。
(大多数表达式的语法规则遵循上述结构,但也有例外情况。例如,用于括号的语法规则不遵循“高优先级表达式内部不包含低优先级运算符”的结构,这就是为什么你可以写像3 * (4 + 5)
这样的表达式。指数运算也是一种例外 - **
在左边比一元的+
/-
/~
运算符更紧密地绑定,但在右边不是,因此**
和一元+
/-
/~
的规则不遵循明确的优先级层次结构。)
(not True) * True
,第二行应该是True * (not True)
。在第二行中,你正在将True
和not
相乘,这是一个语法错误。not
不是函数,所以在它后面不需要使用圆括号。 - MattDMoTrue * not True
会产生相同的语法错误。 - John Kugelman