Python 3.5运算符优先级与完整列表

Hazel
Hazel
发布时间:2026-10-31 | 6人浏览过
原创

全面梳理Python 3.5官方规范中的运算符优先级完整列表,深入剖析17个优先层级、右结合律陷阱、链式比较机制以及Python 3.5新增的矩阵乘法(@)与异步await运算符在优先级中的精确位置与工程最佳实践。

核心要点:在 Python 3.5 中,表达式求值严格遵循运算符优先级与结合律规则。Python 3.5 相比早期版本引入了两个至关重要的语法变动:PEP 465 矩阵乘法运算符 @(位于与乘除整除取模相同的级别)以及 PEP 492 异步协程等待表达式 await(紧随括号与属性访问之后的高绑定级别)。掌握这套体系不仅有助于透彻理解复杂算式的真实运行逻辑,更是规避隐蔽 Bug、编写高可读性 Python 代码的基础。
Python 3.5运算符优先级与完整列表
图 0:Python 3.5 运算符优先级核心全景概览

一、Python 3.5 运算符完整优先级列表

在 Python 语法体系中,当多个运算符出现在同一表达式中时,解释器根据优先级(Precedence)决定运算对象的归属与语法树(AST)的分支结构。优先级越高,运算符越先与两侧的操作数结合;同优先级的双目运算符则依靠结合律(Associativity)决定自左向右还是自右向左执行。

下表依据 Python 3.5 官方语言参考手册(Python Language Reference §6.16 Operator Precedence)整理,从最高优先级(最先绑定)到最低优先级(最后绑定)依次完整排列:

层级 运算符与语法结构 语义描述 结合方向 Python 3.5 备注
1 (expressions...)
[expressions...]
{key: value...}
{expressions...}
绑定圆括号、列表显示、字典显示、集合显示 从左至右 最高优先级原语
2 x[index]
x[index:index]
x(arguments...)
x.attribute
索引下标(Subscription)
切片(Slicing)
函数/类调用(Call)
属性引用(Attribute reference)
从左至右 基元主表达式
3 await x 异步协程挂起等待表达式 从左至右(单目) 3.5 新增 PEP 492
4 ** 指数幂运算(Exponentiation) 从右至左 核心右结合运算符
5 +x, -x, ~x 一元正号、一元负号、按位取反(Bitwise NOT) 从右至左(单目) 紧随幂运算之下
6 *, @, /, //, % 乘法、矩阵乘法、真除法、整除、求模取余 从左至右 3.5 新增 @ PEP 465
7 +, - 双目加法、双目减法 从左至右 常规加减运算
8 <<, >> 按位左移、按位右移 从左至右 整数二进制位移
9 & 按位与(Bitwise AND) 从左至右 二进制掩码
10 ^ 按位异或(Bitwise XOR) 从左至右 二进制翻转
11 | 按位或(Bitwise OR) 从左至右 低于按位与和异或
12 in, not in
is, is not
<, <=, >, >=, !=, ==
包含关系测试
对象同一性判断
大小与相等性比较
链式比较 全部同级,支持短路链式评估
13 not x 布尔逻辑非(Boolean NOT) 从右至左(单目) 单目布尔反转
14 and 布尔逻辑与(Boolean AND) 从左至右 具短路特性
15 or 布尔逻辑或(Boolean OR) 从左至右 具短路特性
16 if – else 条件表达式(三元运算符,Ternary operator) 从左至右 x if C else y
17 lambda 匿名函数表达式(Lambda expression) 从左至右 语法层级最低

注意区分语句与运算符:在 Python 3.5 中,赋值操作(如 =、+=、-=、*= 等)属于赋值语句(Assignment Statements),而不是返回求值结果的表达式运算符(海象运算符 := 直到 Python 3.8 才被引入)。因此,赋值符号不参与上述 17 级优先级比较。

二、Python 3.5 关键变动与新增运算符解析

Python 3.5 在语言规范中引入了两项重磅特性,直接在核心语法与运算符层级中占据了重要席位:矩阵乘法专用运算符 @(PEP 465)与原生协程关键字 await(PEP 492)。理解它们在层级中的精确定位对于编写现代异步与科学计算程序至关重要。

Python 3.5运算符优先级与完整列表
图 1:Python 3.5 新增运算符在语法优先级体系中的锚定位置与作用机制

1. PEP 465 矩阵乘法运算符 @

在 Python 3.5 之前,多维数组与矩阵的点积或乘法通常通过函数形式(如 numpy.dot(A, B))或专门的 np.matrix 对象的 * 重载来实现。这导致当遇到复杂的矩阵公式(例如高斯变换或卡尔曼滤波中的 $A B + C D$)时,代码充斥着层层嵌套的括号,可读性极差。

Python 3.5 官方确立了专用中缀二元运算符 @:

  • 优先级归属:@ 与常规乘法 *、除法 /、整除 //、取模 % 完全同属第 6 级,严格遵循从左至右的结合顺序。
  • 底层数据模型协议:在类中通过实现特殊方法 __matmul__(self, other)、反向方法 __rmatmul__(self, other) 以及增量就地赋值 __imatmul__(self, other)(对应 @=)进行自定义。
  • 内置类型限制:Python 原生内置的标量类型(如 int、float、list)并未实现 @ 协议,若直接对普通整数使用 2 @ 3 会抛出 TypeError: unsupported operand type(s) for @。它专为 NumPy、SciPy、TensorFlow 等数学计算库设计。
# Python 3.5 矩阵运算示例
import numpy as np

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
bias = np.array([[1, 1], [1, 1]])

# @ 优先级高于 +,无需额外添加括号
result = A @ B + bias
# 等价于 (A @ B) + bias

2. PEP 492 异步等待表达式 await

Python 3.5 正式引入了原生的 async def 和 await 语法,将协程从依赖生成器(yield from)的过渡方案转变为语言内置的一等公民。在语法定义中,await x 被定义为表达式(Expression)而非单独语句:

  • 优先级归属:位于第 3 级,仅仅低于括号、容器定义与主表达式(x[i]、x(...)、x.attr),但高于幂运算 **、一元运算符以及所有常规四则运算。
  • 语法绑定表现:await task() + 5 会被严格解析为 (await task()) + 5,而绝非 await (task() + 5)。这保证了协程的结果在返回后能无缝参与后续的外层算术或逻辑运算。
  • 作用域限制:await 只能出现在使用 async def 定义的协程函数体内部,在常规同步函数中使用会触发 SyntaxError。

三、表达式推导与求值顺序剖析

许多初学者容易将“运算符优先级”与“操作数求值顺序”混为一谈。在 Python 中,这两者有明确的分工:优先级决定了语法树的嵌套结构(谁是谁的操作数),而操作数的求值始终严格按照从左到右的顺序进行。

我们以一个综合算式为例进行完整语法推导:

-3 ** 2 + 5 * 2 @ M < 100 and not flag
Python 3.5运算符优先级与完整列表
图 2:综合算式在 Python 解释器中的分层推导与归约流程

该表达式的严谨规约步骤如下:

  1. 第一阶段(幂运算):扫描到 -3 ** 2。由于 **(Level 4)高于一元负号 -(Level 5),语法树将 3 ** 2 结合为一个子节点,计算为 9;随后负号作用其上,得到 -9。
  2. 第二阶段(乘除与矩阵乘法):子表达式 5 * 2 @ M 中,* 与 @ 同处 Level 6 且左结合,因此先计算标量乘法 5 * 2 = 10,紧接着执行矩阵乘法 10 @ M。
  3. 第三阶段(加减运算):加法 +(Level 7)将左侧的 -9 与右侧的 10 @ M 连接,生成结果 -9 + (10 @ M)。
  4. 第四阶段(比较运算):小于号 <(Level 12)将上述矩阵加法结果与数值 100 进行比较,产生布尔矩阵或布尔值。
  5. 第五阶段(逻辑非与逻辑与):单目逻辑非 not flag(Level 13)优先于逻辑与 and(Level 14)执行;最后 and 运算符对左侧比较结果与右侧布尔值进行最终逻辑合并。

四、高频优先级陷阱与边界案例

即便熟读优先级表格,在编写某些特殊算式时,人脑的数学直觉仍容易与解释器的规约规则发生冲突。以下梳理三个最常见的经典陷阱及其规避方案:

Python 3.5运算符优先级与完整列表
图 3:运算符高频陷阱案例分析与正确防御写法

陷阱 1:幂运算符 ** 的唯一右结合特性

绝大部分二元运算符(如 -、/、%、@)均是从左到右结合,例如 8 / 4 / 2 等价于 (8 / 4) / 2 = 1.0。但幂运算符 ** 遵循数学惯例,是 Python 唯一的二元右结合运算符:

# 右结合推导
result = 2 ** 3 ** 2

# 错误直觉(从左至右):(2 ** 3) ** 2 = 8 ** 2 = 64
# 实际执行(从右至左):2 ** (3 ** 2) = 2 ** 9 = 512
print(result)  # 输出: 512
防御建议
任何涉及两层以上的指数运算,严禁依赖默认结合律裸写,务必使用显式圆括号清晰标注计算意图,如 (x ** y) ** z 或 x ** (y ** z)。

陷阱 2:单目负号在幂运算左右侧的非对称行为

在代数书写中,$-2^2$ 经常造成理解混淆。在 Python 中,单目负号 - 的优先级严格低于其右侧的幂运算,但其作为右操作数时又紧密依附于右侧底数:

# 负号在左侧:幂运算优先,负号后作用
print(-2 ** 2)    # 实际执行 -(2 ** 2) => -4,而非 (-2) ** 2 = 4

# 负号在右侧:负号作为右操作数一元符号紧密绑定
print(2 ** -2)    # 实际执行 2 ** (-2) => 0.25

如果希望以负数作为幂运算的底数,必须严格书写 (-2) ** 2。

陷阱 3:按位运算符(&, |, ^)与比较运算符的次序倒置

在许多低级语言或嵌入式场景中,开发者常需要通过位掩码检查状态标志位:

# 检查状态值 status 的最后一位是否为 0
status = 4
if status & 1 == 0:
    print("末位为0")

上述代码会产生隐蔽的逻辑错误。因为比较运算符 ==(Level 12)的优先级高于按位与 &(Level 9)。解释器实际执行的代码是:

# 实际等价代码:
status & (1 == 0)  =>  status & False  =>  4 & 0  =>  0
# 在 if 条件判断中,0 被判定为假(Falsy),导致分支永不执行!

正确的防御性写法必须对位运算加上括号:if (status & 1) == 0:。

陷阱 4:链式比较的短路与单次求值机制

Python 支持极其直观的数学连续比较语法,如 1 < x < 10。根据规范,所有比较运算符(包括 in、is、<、== 等)具有完全相同的优先级。链式比较在语法层面具有以下关键特性:

  • a < b < c 严格等价于 (a < b) and (b < c)。
  • 单次求值保证:位于中间的表达式 b 仅被求值一次。即便 b 是一个包含耗时计算或副作用的函数调用(如 get_val()),解释器也绝不会执行两次。
  • 短路终止:若左侧的 a < b 判定为 False,右侧的 b < c 将被完全短路跳过,根本不会执行。

五、Python 3.5 运算符速查体系与工程最佳实践

为了便于日常编码快速查阅与团队代码审查,我们将 Python 3.5 所有的运算层级归纳为结构清晰的八大阶梯全景图:

Python 3.5运算符优先级与完整列表
图 4:Python 3.5 运算符全景金字塔与记忆口诀速查

工程落地规范:PEP 8 关于运算符与括号的指导

在大型工程实践中,虽然编译器和解释器对优先级有严丝合缝的规约规则,但人脑在代码速读与维护时的记忆负荷是有限的。PEP 8 官方代码风格指南明确给出了以下原则:

  1. 不要炫技,善用圆括号消除歧义:当一个算式混合了算术、位运算与逻辑运算时,即使你 100% 笃定优先级顺序,也应主动包裹圆括号。代码阅读的清晰度永远优先于省去两个字符。
  2. 运算符两侧的空格规范:当在一个表达式中存在不同优先级的运算符时,建议在最低优先级的运算符周围保留空格,而在高优先级的运算符两侧省略空格(或保持对称紧凑),直观体现逻辑聚拢度。
    # 推荐写法:高优先级运算紧凑,低优先级运算两侧留白
    hypot = x*x + y*y
    c = (a+b) * (a-b)
    
    # 不推荐写法:均匀空格容易掩盖运算层级
    hypot = x * x + y * y
  3. 布尔判断的简洁性:永远不要为了显式比较而写 if flag == True:,应直接书写 if flag:;判断单例对象使用 is 与 is not,而非 ==(例如 if x is None:)。

通过本文对 Python 3.5 完整 17 级优先级序列的梳理、新增 @ 与 await 运算符机制的拆解,以及常见陷阱的对比剖析,读者可以建立起底层清晰的求值心智模型。在今后的开发与代码审查中,既能写出高效准确的底层算法,又能保证整个工程的健壮与规范。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表