HOWTO · Python

Python 中的运算顺序

本教程讨论 Python 中运算符的执行顺序,涵盖运算符优先级、算术运算符、逻辑运算符,以及使用括号使意图更清晰。扎实理解 Python 如何求值表达式,从而编写更好的代码并避免常见陷阱。

本页内容

Python 按照优先级求值运算符,因此乘法和除法的结合比加法和减法更紧密。要预测结果,请先按优先级将表达式分组,然后考虑结合性以及任何短路逻辑运算符。括号使预期的分组变得明确。

什么是运算符优先级?

运算符优先级是 Python 用来对表达式的各部分进行分组的优先顺序。它描述的是分组,而不是一个通用的从左到右执行顺序:结合性决定具有相同优先级的运算符如何分组,Python 按其指定的顺序求值操作数。例如,3 + 4 * 2 分组为 3 + (4 * 2),值为 11。

以下参考列出了常见的 Python 运算符,从高优先级到低优先级。同一行中的运算符共享一个优先级级别;请使用结合性规则或括号来确定它们的分组。

优先级,从高到低 运算符或表达式
分组与访问 (expressions), x[index], x(...), x.attribute
Await await x
幂运算 **
一元数值与位运算 +x, -x, ~x
乘法 *, @, /, //, %
加法 +, -
位移 <<, >>
位与 AND &
位异或 XOR ^
位或 OR `
比较与成员/身份测试 <, <=, >, >=, !=, ==, in, not in, is, is not
布尔 NOT not x
布尔 AND and
布尔 OR or
条件表达式 x if condition else y
Lambda lambda
赋值表达式 :=

这是针对本文所讨论运算符的实用参考,而不是每种表达形式的完整语法。PEMDAS 是一个常见的算术记忆法,但它并未描述所有 Python 运算符,也不能取代上述优先级规则。幂运算还会从右到左分组,因此 2 ** 3 ** 2 意指 2 ** (3 ** 2)。一元正负号与幂运算之间有特殊关系:-2 ** 2 分组为 -(2 ** 2)。

基本算术运算符

在算术中,括号最先分组;其次是幂运算;然后是乘法、除法、整除和取模;最后是加法和减法。乘法和除法具有相同的优先级,并从左到右结合,加法和减法也是如此。/ 运算符执行真正的除法,因此整数相除可以产生浮点数。

运行此示例:

a = 10
b = 5
c = 2

mixed = a + b * c - a / b
explicit = (a + b) * c - a / b
print(mixed)
print(explicit)

第一个表达式分组为 10 + (5 * 2) - (10 / 5);第二个表达式分组为 (10 + 5) * 2 - (10 / 5)。除法产生浮点值,因此最终值为浮点数。此示例尚未执行,因此其输出未在此处显示。

相同的规则可以解释 10 + 2 / 2:除法先被分组,因此值为 11。Python 并不会仅仅因为加法在表达式中先出现就先选择加法。

使用括号使意图更清晰

括号建立分组,并可以改变结果。在上面的例子中,(a + b) 在乘法之前被分组,这改变了与没有括号的表达式相比的算术。当括号可以使您预期的计算更清晰时,请加上它们,即使 Python 的默认优先级已经会产生相同的分组。

括号控制分组;它们并不意味着表达式的每个部分都被急切地求值。Python 仍然遵循每个运算符的语义,包括 and 和 or 的短路行为。

比较与逻辑运算符

==、!=、<、<=、> 和 >= 等比较的优先级高于 not、and 和 or。括号有助于显示哪些比较会输入到逻辑表达式中。例如,(10 > 5) and (15 > 10) 结合了两个为真的比较,因此该表达式为真。

not 适用于其后的表达式,且结合比 and 更紧密;and 的结合比 or 更紧密。and 和 or 都会短路:当左侧操作数决定结果时,Python 可以跳过对右侧操作数的求值。它们还会返回其操作数之一,而不是总是返回布尔值。在条件中,Python 根据其真值来处理结果值。

对于可读的条件,请编写明确的分组,例如 (age >= 18) and (has_ticket or is_guest)。这使预期的关系变得清晰,并有助于防止将优先级规则误认为业务规则。

链式比较

Python 支持诸如 10 > 5 > 15 的比较链。这在结果上等同于 10 > 5 and 5 > 15,中间的表达式只求值一次。第一个比较为真,第二个比较为假,因此整个链为假。Python 并不会将 10 > 5 的布尔结果与 15 进行比较。

链对于范围检查非常有用:0 <= score <= 100 要求两个比较都为真。如果比较涉及不同的表达式,或者中间值应被求值多次,请明确编写预期的比较,并在能提高清晰度的情况下使用临时变量。

结论

要预测 Python 表达式,请应用运算符优先级规则,在运算符共享一个级别时检查结合性,并考虑短路等行为。使用括号来传达您预期的分组。这些习惯使算术和条件表达式更易于阅读和调试。

常见问题

  1. Python 中的运算符优先级是什么?

    它是 Python 用来对表达式中的运算符进行分组的优先级。结合性和每个运算符的语义也会影响表达式的求值方式。

  2. 如何更改表达式的分组?

    在应最先分组的子表达式周围加上括号,例如 (a + b) * c。

  3. 当运算符具有相同优先级时会发生什么?

    这取决于运算符。大多数运算符从左到右分组,幂运算从右到左分组,比较可以形成链。当分组可能不明确时,请添加括号。

  4. 如果我在复杂表达式中省略括号会怎样?

    Python 会应用其定义的优先级和结合性规则。如果该分组难以看清,请添加括号以使预期的计算变得明确。

  5. 我可以链接比较运算符吗?

    可以。像 0 <= score <= 100 这样的链会检查这两个比较,并对中间的表达式求值一次。