Python 负常数与运算符优先级

Python 负常数与运算符优先级,python,Python,我已经用Python编程多年了,但一些非常琐碎的事情让我吃惊: -1**2 -1 当然,对任何负实数求平方都会产生一个正结果。也许Python的数学并没有完全崩溃。让我们看看它是如何解析这个表达式的: ast.dump(ast.parse('-1**2').body[0]) Expr( 值=UnaryOp( op=USub(), 操作数=BinOp( 左=Num(n=1), op=Pow(), 右=Num(n=2) ) ) ) 好的,它把它当作是我写的-(1**2)。但是为什么-前缀被视为一

我已经用Python编程多年了,但一些非常琐碎的事情让我吃惊:

-1**2
-1
当然,对任何负实数求平方都会产生一个正结果。也许Python的数学并没有完全崩溃。让我们看看它是如何解析这个表达式的:

ast.dump(ast.parse('-1**2').body[0]) Expr( 值=UnaryOp( op=USub(), 操作数=BinOp( 左=Num(n=1), op=Pow(), 右=Num(n=2) ) ) ) 好的,它把它当作是我写的
-(1**2)
。但是为什么
-
前缀被视为一个单独的一元减法运算符,而不是常量的符号

请注意,表达式
-1
不是解析为常量
1
的一元减法,而是解析为常量
-1

ast.dump(ast.parse('-1').body[0]) Expr( 值=Num(n=-1) ) 这同样适用于
-1*2
,尽管它在语法上与第一个表达式几乎相同

ast.dump(ast.parse('-1*2').body[0]) Expr( value=BinOp( 左=Num(n=-1), op=Mult(), 右=Num(n=2) ) )

这种行为在许多语言中都很常见,包括perl、PHP和Ruby。

它的行为就像文档中解释的那样:

2.4.4。数字文字

[…]注意数字文字不包括符号;像
-1
这样的短语实际上是由一元运算符
-
和文本
1
组成的表达式

以及:

6.5。电力操作员

幂运算符比一元运算符在其上绑定得更紧密 左边[……]


另请参见中的优先级表。以下是该表中的相关部分:

运算符|说明
-------------|---------------------------------
*|乘法。。。
+x、 -x,~x |正,负,按位非
**|指数化

这解释了为什么解析树在
**
*
示例之间不同。

我认为您的第三个代码块有输入错误,应该是
ast.parse('-1')
,是吗?修复了,谢谢@Blorgbeard.@RyanGovostes我怀疑这是一个优化。即使它在语义上是一个运算符,但当它看到它周围的运算符具有较低的优先级时,它会将其视为一个文本负数?在3.6.8中,它按预期工作(添加了否定的
UnOp
)。我不确定为什么
-1
在我包含的其他两个表达式中都没有被解析为“常数1的一元否定”。这里还有一个重要部分:“请注意,数字文字不包括符号;像
-1
这样的短语实际上是由一元运算符
-
和文本
1
“@RyanGovostes一元运算符在乘法和求幂之间具有优先权,这就是为什么您的示例对
*
**
的效果不同的原因(请参阅我更新的答案)。Python语言可能并不完美,但不久前有人建立了它的规则,至少在这方面他们坚持为该语言设置的规则。对。我想这是@Barmar建议的,并且USub(Num)子树不断发生折叠。(但为什么不折叠整个表达式?)包含如何以及何时应用此类优化的逻辑。