知识点

Python运算符优先级

定义

一个表达式里出现多个运算符时,需要一套规则决定先算哪一部分。优先级决定不同级别运算符的先后,优先级高的先结合;结合性决定同一优先级的运算符如何分组。括号可以强制改变默认顺序,写在括号里的部分总是先算。

下表按优先级从高到低排列,同一行的运算符优先级相同:

运算符描述示例或备注
(...)、[...]、{...}括号、列表、字典与集合的显示优先级最高
x[i]、x[i:j]、x.attr、f(...)下标、切片、属性、函数调用
**幂运算2**3**2等于2**(3**2) = 512,右结合
~、+x、-x按位取反、正负号一元运算符
*、/、//、%乘、除、整除、取模// 向下取整
+、-加、减
<<、>>移位
&按位与
^按位异或
|按位或
in、not in、is、is not、<、<=、>、>=、!=、==比较运算符优先级相同,支持链式比较a < b < c
not逻辑非
and逻辑与短路:False and x不计算x
or逻辑或短路:True or x不计算x
if–else条件表达式x if c else y
lambdaLambda表达式
:=海象运算符,Python 3.8+优先级最低

这张表只适用于Python。C使用不同的运算符集合与优先级,参见C运算符优先级。

性质

同级运算的结合方向

同一行的运算符一般从左到右结合,例如10 - 3 - 2先算10 - 3,再减2。幂运算 ** 是主要例外,从右到左结合,所以连写多个 ** 时要从最右边的一组算起。

结合方向只决定分组,不改变优先级:2 * 3 ** 2先算幂再算乘法,因为 ** 的优先级更高。

括号改变求值顺序

括号内的表达式整体先算,再参与外层运算。表里的顺序只是“不加括号时的默认分组”;需要别的顺序时加括号即可,不必背下整张表再心算。

逻辑运算的短路

and与or从左到右求值,一旦结果已经确定就停下来:

  • and左边为假时,右边不再计算,结果就是左边的值;
  • or左边为真时,右边不再计算,结果就是左边的值。

短路不只是省时间:右边如果带副作用或会抛异常,短路时这些代码根本不会执行。例如True or 1 / 0不会触发ZeroDivisionError。

比较运算可以链式书写

比较运算符优先级相同,并且支持链式写法:a < b < c等价于a < b and b < c,中间的操作数只求值一次。它不表示先算a < b再把布尔结果与c比较。

易错点

例子

幂与一元负号:-3**2

** 的优先级高于一元负号,-3**2先算3**2 = 9,再取负,结果是 -9。想要 99 必须写成 (-3)**2。

幂运算右结合:2**3**2

** 从右到左结合,2**3**2等价于2**(3**2) = 2^9 = 512,而不是 (2**3)**2 = 64。

比较先于逻辑非:not a == b

比较运算符的优先级高于not,所以not a == b等价于not (a == b)。如果本意是先取反再比较,必须写成 (not a) == b。

and先于or:a and b or c

and的优先级高于or,所以a and b or c等价于 (a and b) or c:先求a and b,结果再与c做or。

在解释器里核对分组

precedence.py
print(2 ** 3 ** 2) # 512
print(-3 ** 2) # -9
print(not 1 == 2) # True
print(True or 1 / 0) # True,右侧没有被求值

探索

负号和幂运算怎样分组?

改变指数,比较负号在括号内外的结果。

正在准备演示…

题集

练习

  1. -3**2的值是 。

    参考解答

    ** 优先于一元负号,先算3**2 = 9,再取负得到 -9。

  2. 2**3**2的值是 。

    参考解答

    幂运算右结合,等价于2**(3**2) = 2^9 = 512。

  3. not 1 == 2的结果是:

    选择答案
    参考解答

    比较先算,1 == 2为False,再取非得到True。

  4. True and False or True的结果是:

    选择答案
    参考解答

    and先算,True and False为False,再与True做or,结果为True。

  5. 关于and、or的求值,下列说法正确的是:

    题 short-circuit · choice
    参考解答

    短路规则使A、B成立;表中and高于or,C成立。比较运算符的优先级高于not、and、or,D不成立。