Python 运算符优先级
Python的文档说,*
(乘法)和/
(除法)是同级别的运算符。
我知道在Python中,表达式是从左到右计算的。
那么我可以依靠这个规则,假设j*j/m
总是等于(j*j)/m
,也就是可以不加括号吗?
如果是这样的话,我能否认为对于同级别的运算符,这个规则都是适用的呢?
补充说明:这个问题对我来说是合适的,
我在阅读只使用整数的代码(像上面的例子)时,发现没有括号,这让我当时觉得很可疑。
3 个回答
简短的回答是:是的。
同一类的运算符优先级是一样的。除非特别说明,否则运算符都是二元的。同一类的运算符从左到右进行分组(比较运算符除外,包括测试,这些运算符优先级相同,并且从左到右链式连接……而指数运算符则是从右到左分组)。
换句话说,你的问题的答案是肯定的,优先级相同的运算符会从左到右分组,除了比较运算符,它们是链式连接而不是分组:
>>> x = 0
>>> y = 0
>>> x == y == True
False
>>> (x == y) == True
True
>>> x == (y == True)
True
还有指数运算:
>>> 2 ** 2 ** 3
256
>>> (2 ** 2) ** 3
64
>>> 2 ** (2 ** 3)
256
另外,在赋值时,右边的表达式会先计算,然后再计算左边的:
>>> x = 1
>>> y = x = 2
>>> y
2
但是,如果对你这个编码者来说有些模糊,那肯定是因为你在问问题,所以可以预期读代码的人也会感到模糊。为了让他们更清楚,最好多花几个字节来解释一下。
依赖优先级规则对于编译器来说是不错的,但对普通人来说就不一定了。
对评论的补充回应:
对于那些在阅读代码时遇到模糊情况,需要查阅外部资料来确认的人,你应该假设下一个读者的水平可能不如你,因此最好为他们添加括号,省去他们的麻烦,避免不必要的错误。
实际上,连被接受的答案都有错误(在理由上,而不是结果上,见它的第一条评论),我之前并不知道,很多点赞的人也不知道。
关于基础代数的说法,原帖中用的例子很有启发性。不管运算符的优先级如何,表达式 j * (j / m)
在代数上和 (j * j) / m
是相同的。不幸的是,Python 的代数只是“理想代数”的一种近似,这可能会导致根据 j
和 m
的大小,任一形式都可能得出错误的结果。例如:
>>> m = 1e306
>>> m
1e+306
>>> j = 1e307
>>> j
9.9999999999999999e+306
>>> j / m
10.0
>>> j*j
inf
>>> j * (j / m)
1e+308
>>> (j * j) / m
inf
>>> ((j * j) / m) == (j * (j/m))
False
所以,实际上 Python(以及我的浮点运算单元)的准代数的恒等性质并不成立。而且在你的机器上可能会有所不同,因为文档中提到:
浮点数在 C 语言中是用双精度实现的。除非你知道自己正在使用的机器,否则它们的精度就无法保证。
可以说,处理溢出边缘的事情不太合适,这在某种程度上是对的,但如果脱离上下文,表达式在一种运算顺序下是未确定的,而在另一种运算顺序下又是“正确”的。
没错,优先级相同的运算符是从左到右进行计算的,也就是说,最左边的两个项会先进行运算,然后把结果和第三个项再运算,以此类推。
不过有一个例外,就是 **
这个运算符:
>>> 2 ** 2 ** 3
256
另外,比较运算符(比如 ==
、>
等等)并不是按照关联性来运算的,而是把 x [cmp] y [cmp] z
转换成 (x [cmp] y) and (y [cmp] z)
这样的形式。