Python运算符有哪几种?7类运算符分类与符号详解
全面解析Python中的7大类运算符:算术、比较、赋值、逻辑、位运算、成员与身份运算符。详解符号含义、代码示例、短路求值机制、is与==底层内存差异及优先级规则。
is 与 == 的底层区别,是编写稳健、无隐蔽 Bug 程序的必修基础。
一、Python 运算符整体分类架构
在 Python 语言中,“一切皆对象”(PyObject)。所有运算符在底层实际上都会被转换为对应的特殊魔法方法调用(如 + 对应 __add__,== 对应 __eq__,in 对应 __contains__)。根据计算特征与返回值类型,这 7 类运算符可归纳为两大形态:数值加工与状态变更类(算术、位运算、赋值)与关系断言与条件判定类(比较、逻辑、成员、身份)。
二、第一类:算术运算符 (Arithmetic Operators)
算术运算符主要用于对数值型数据(整数 int、浮点数 float、复数 complex)执行日常数学计算。Python 提供了 7 种算术运算符:
| 符号 | 运算符名称 | 示例算式 | 运算结果 | 机制说明 |
|---|---|---|---|---|
+ |
加法 | 5 + 3 |
8 |
两数相加;对字符串/列表则表示拼接 |
- |
减法 | 10 - 4.5 |
5.5 |
两数相减,或表示一元负号 -x |
* |
乘法 | 3 * 4 |
12 |
两数相乘;对序列表示重复 |
/ |
真除法 | 7 / 2 |
3.5 |
结果恒为 float,即便能整除(如 4 / 2 == 2.0) |
// |
整除(地板除) | 7 // 2 |
3 |
向下取整(向负无穷方向舍入) |
% |
取模(求余) | 7 % 2 |
1 |
计算整除后的余数,满足 r = a - (a // b) * b |
** |
幂运算 | 2 ** 3 |
8 |
等价于 pow(2, 3),计算指数次方 |
代码示例与输出
# 基础算术运算
a = 14
b = 4
print("真除法 a / b =", a / b)
print("整除 a // b =", a // b)
print("取模 a % b =", a % b)
print("幂运算 a ** 2 =", a ** 2)
# 负数整除与取模特征
neg_a = -14
print("负数整除 -14 // 4 =", neg_a // b)
print("负数取模 -14 % 4 =", neg_a % b)
整除 a // b = 3
取模 a % b = 2
幂运算 a ** 2 = 196
负数整除 -14 // 4 = -4
负数取模 -14 % 4 = 2
// 是“向下取整”(Floor Division,向负无穷方向取整),而不是像 C/Java 那样“截断取整”(向零舍入)。因此 -14 // 4 得到的是 -4 而非 -3。依据余数公式 r = a - (a // b) * b,-14 - (-4 * 4) = 2,因此负数取模结果在除数为正时仍为正数。
三、第二类:比较(关系)运算符 (Comparison Operators)
比较运算符用于评估两个操作数之间的关系大小,其返回结果始终为布尔值(True 或 False)。
| 符号 | 关系说明 | 成立条件 | 示例 |
|---|---|---|---|
== |
等于 | 两边操作数的值相等 | 5 == 5.0 => True |
!= |
不等于 | 两边操作数的值不相等 | 'a' != 'b' => True |
> |
大于 | 左侧数值或字典序大于右侧 | 10 > 3 => True |
< |
小于 | 左侧数值或字典序小于右侧 | 2 < 8 => True |
>= |
大于或等于 | 左侧大于或等于右侧 | 5 >= 5 => True |
<= |
小于或等于 | 左侧小于或等于右侧 | 3 <= 4 => True |
Python 特色:链式比较 (Chained Comparison)
在其他多数编程语言中,写出 18 <= age <= 60 会被拆解为 (18 <= age) <= 60,即 True <= 60(转换为 1 <= 60,造成恒为真的严重逻辑错误)。而 Python 在语法层面对链式比较提供了原生支持:
age = 25
# 链式比较优雅且符合数学书写习惯
is_working_age = 18 <= age <= 60
print("是否在工作年龄段:", is_working_age)
# 等价于 (18 <= age) and (age <= 60),但中间的 age 只求值一次
def get_score():
print("[执行] get_score() 被调用")
return 88
# 链式比较验证
valid_score = 60 <= get_score() <= 100
[执行] get_score() 被调用
注意看上面的输出:get_score() 仅被调用了 1 次,避免了重复计算开销和潜藏的副作用。
四、第三类:赋值运算符与海象运算符 (Assignment Operators)
赋值运算符负责将右侧表达式的计算结果与左侧的变量名建立绑定关系。除了基础赋值号 = 之外,Python 支持多种与算术或位运算结合的复合赋值运算符,并在 Python 3.8 引入了重要的“海象运算符”。
| 符号 | 语法形态 | 展开等价形式 | 说明 |
|---|---|---|---|
= |
x = 10 |
基础赋值 | 将变量名 x 绑定到对象 10 |
+= |
x += 5 |
x = x + 5 |
加后赋值(对可变列表优先调用 __iadd__ 就地修改) |
-=, *=, /= |
x *= 2 |
x = x * 2 |
减后赋值、乘后赋值、除后赋值 |
//=, %=, **= |
x %= 3 |
x = x % 3 |
整除后赋值、取模后赋值、幂后赋值 |
&=, |=, ^= |
x &= 0b11 |
x = x & 0b11 |
复合位运算赋值 |
<<=, >>= |
x <<= 2 |
x = x << 2 |
复合移位赋值 |
:= |
(n := len(s)) > 5 |
海象运算符(表达式内赋值) | 赋值的同时返回该值,可在条件分支中直接使用 |
海象运算符 (Walrus Operator :=) 实战场景
海象运算符解决了“先计算赋值、再进行条件判断”产生的代码冗余问题,特别适合循环读取和避免重复计算:
# 场景:匹配特定格式文本并提取长度
message = "Python_Data_Processing_2026"
# 传统写法需要先计算赋值,或在 if 内部再次调用 len()
# 使用海象运算符 := 在 if 判断中同时完成计算与变量绑定
if (length := len(message)) > 10:
print(f"文本超长(长度为 {length}),触发分卷处理")
五、第四类:逻辑运算符与短路求值机制 (Logical Operators)
Python 提供了 3 个逻辑运算符:and(与)、or(或)以及 not(非)。它们不仅处理严格的布尔值 True / False,还能作用于 Python 中的任意对象。
1. 真值判定 (Truth Value Testing)
在 Python 中,下列值在布尔上下文中被视为假 (Falsy):
- 常量:
None、False - 数值零:
0、0.0、0j、Decimal(0) - 空序列与空集合:
""(空字符串)、()(空元组)、[](空列表)、{}(空字典)、set()(空集合)
除上述以外的所有对象,默认均为真 (Truthy)。
2. 核心特性:短路求值 (Short-Circuit Evaluation)
逻辑运算符 and 和 or 并不总是返回布尔值,而是直接返回最终决定表达式结果的操作数对象本身:
A and B:首先评估A。若A为假,则整个表达式必然为假,立即返回A(短路),完全不执行B;若A为真,则继续评估并返回B。X or Y:首先评估X。若X为真,则整个表达式必然为真,立即返回X(短路),完全不执行Y;若X为假,则继续评估并返回Y。not X:对X的真假取反,其返回值恒为严格布尔值True或False。
短路求值代码演示
# 默认值回退模式 (Fallback Pattern)
user_input = ""
display_name = user_input or "匿名访客"
print("显示名称:", display_name)
# 防空指针异常保护 (Guard Pattern)
user = None
# 若 user 为 None,短路机制会在左侧立刻停下,不会触发 AttributeError
profile = user and user.get("profile")
print("安全访问结果:", profile)
# 返回值是原对象而非 True/False
print("3 and 'hello' ->", repr(3 and 'hello'))
print("[] or [1, 2, 3] ->", repr([] or [1, 2, 3]))
安全访问结果: None
3 and 'hello' -> 'hello'
[] or [1, 2, 3] -> [1, 2, 3]
六、第五类:位运算符 (Bitwise Operators)
位运算符直接对整数的二进制补码(Two's Complement)进行操作。它们执行速度极快,常用于权限系统设计、硬件协议通信、数据压缩及高性能掩码计算。
| 符号 | 名称 | 规则描述 | 示例 (8位二进制运算) |
|---|---|---|---|
& |
按位与 | 两个对应位都为 1 时结果才为 1 | 0b1100 & 0b1010 => 0b1000 (8) |
| |
按位或 | 只要有一个对应位为 1 结果就为 1 | 0b1100 | 0b1010 => 0b1110 (14) |
^ |
按位异或 | 对应位数值不同为 1,相同为 0 | 0b1100 ^ 0b1010 => 0b0110 (6) |
~ |
按位取反 | 按位翻转(0变1,1变0),数学上满足 ~x = -(x + 1) |
~5 => -6 |
<< |
左移 | 各二进制位向左移动 n 位,右侧补0,相当于乘以 2ⁿ | 3 << 2 => 12 (3 * 4) |
>> |
右移 | 各二进制位向右移动 n 位,相当于整除 2ⁿ | 16 >> 2 => 4 (16 // 4) |
位运算实战:基于二进制标志位的权限系统
# 定义基于位掩码的读写执行权限
PERMISSION_READ = 1 << 0 # 0b001 = 1
PERMISSION_WRITE = 1 << 1 # 0b010 = 2
PERMISSION_EXECUTE = 1 << 2 # 0b100 = 4
# 赋予用户:读 + 执行 权限 (使用按位或 |)
user_perms = PERMISSION_READ | PERMISSION_EXECUTE # 0b101 = 5
# 检查是否具有写权限 (使用按位与 &)
has_write = bool(user_perms & PERMISSION_WRITE)
print("具有写权限:", has_write)
# 检查是否具有读权限
has_read = bool(user_perms & PERMISSION_READ)
print("具有读权限:", has_read)
具有读权限: True
七、第六类:成员运算符 (Membership Operators)
成员运算符用于测试指定序列或容器对象中是否包含目标元素。包含两种形式:
in:如果指定的元素存在于容器序列中,返回True,否则返回False。not in:如果指定的元素不在容器序列中,返回True,否则返回False。
底层查找性能差异(算法复杂度考量)
虽然语法相同,但在不同数据结构上执行 in 运算的底层时间复杂度存在极大悬殊:
- 列表 (
list) / 元组 (tuple):基于底层连续数组从头至尾遍历查找,平均时间复杂度为 O(n)。当数据量达到百万级别时,耗时显著增加。 - 集合 (
set) / 字典键 (dict):基于哈希表(Hash Table)根据哈希值直接定位,平均时间复杂度为 O(1) 常数时间。
fruits = ["apple", "banana", "cherry"]
print("'apple' in fruits ->", 'apple' in fruits)
print("'grape' not in fruits ->", 'grape' not in fruits)
# 字典的 in 操作默认只检查键 (Key)
user_info = {"name": "Alice", "role": "admin"}
print("'role' in user_info ->", 'role' in user_info)
print("'admin' in user_info ->", 'admin' in user_info) # 不会检索 value
'grape' not in fruits -> True
'role' in user_info -> True
'admin' in user_info -> False
八、第七类:身份运算符 (Identity Operators) 及与 == 的深度对比
身份运算符用于比较两个变量是否引用了物理内存中的同一个对象:
is:判断两个变量引用的对象内存地址是否完全相同(等价于id(a) == id(b))。is not:判断两个变量引用的对象内存地址是否不同。
== 与 is 的本质差别
==是“值比较” (Equality):它调用对象实现的__eq__方法,比较两个对象承载的数据内容是否一致。即使两个对象位于不同的内存地址,只要内容一致,==就会返回True。is是“身份比较” (Identity):它直接检查两个变量指针所指向的物理内存地址(C 语言层面的PyObject*地址)。哪怕两个对象内容完全一模一样,只要它们是由不同堆空间独立分配的,is就必然返回False。
# 案例 1:独立分配的列表对象
list_a = [1, 2, 3]
list_b = [1, 2, 3]
print("值比较: list_a == list_b ->", list_a == list_b)
print("身份比较: list_a is list_b ->", list_a is list_b)
print(f"内存ID: id(list_a)={id(list_a)} vs id(list_b)={id(list_b)}")
# 案例 2:变量引用赋值
list_c = list_a
print("别名绑定: list_a is list_c ->", list_a is list_c)
身份比较: list_a is list_b -> False
内存ID: id(list_a)=4382910400 vs id(list_b)=4382911200
别名绑定: list_a is list_c -> True
初学者容易被小整数池误导:在 CPython 实现中,为了提升性能,-5 到 256 之间的整数在启动时就被预先分配在全局对象池中。因此 100 is 100 会返回 True,但这属于实现层面的内部优化细节,绝不能当作业务规范!一旦数值超过 256(如 1000 is 1000 在不同代码块下),结果将变为 False。
PEP 8 官方权威准则:
- 比较数据、数值、字符串大小或内容是否一致时,务必使用
==。 - 检查单例对象(如
None)时,务必使用if x is None:或if x is not None:,因为is比==执行更快,且能彻底防止类自定义__eq__重载带来的逻辑误判。
九、运算符优先级与计算执行决策模型
当一个复杂表达式中同时混用多种运算符时,Python 依据固定的优先级顺序决定计算先后。如果优先级相同,则按照从左到右的结合性依次计算(唯一例外是幂运算符 **,它具有右结合性,即 2 ** 3 ** 2 == 2 ** (3 ** 2) = 512)。
运算符优先级梯队速查表(从高到低)
| 优先级梯队 | 运算符类别 | 符号表示 | 结合性方向 |
|---|---|---|---|
| 第 1 级 (最高) | 圆括号分组 | ( ), [ ], {} |
从左到右 |
| 第 2 级 | 幂运算 | ** |
从右到左 (右结合) |
| 第 3 级 | 一元运算符 | +x, -x, ~x |
从右到左 |
| 第 4 级 | 乘除、整除、取模 | *, /, //, % |
从左到右 |
| 第 5 级 | 加法、减法 | +, - |
从左到右 |
| 第 6 级 | 二进制位移 | <<, >> |
从左到右 |
| 第 7 级 | 按位与 | & |
从左到右 |
| 第 8 级 | 按位异或 / 按位或 | ^ 然后 | |
从左到右 |
| 第 9 级 | 比较、成员、身份 | ==, !=, <, >, in, is |
从左到右(支持链式) |
| 第 10 级 | 逻辑非 | not |
从左到右 |
| 第 11 级 | 逻辑与 | and |
从左到右(短路) |
| 第 12 级 | 逻辑或 | or |
从左到右(短路) |
| 第 13 级 (最低) | 海象运算符与所有赋值 | :=, =, +=, -= ... |
从右到左 |
虽然 Python 定义了严密的优先级体系,但不要在生产代码中编写高度依赖优先级的隐晦长表达式(如
a + b << c > d and not e or f)。适时添加显式括号 ( ) 不会带来任何性能损耗,不仅能确保执行逻辑绝不走偏,还能极大降低同事阅读和后期维护的心智负担。
十、总结与知识速查 Checklist
掌握 Python 运算符的核心关键在于厘清每类的设计目的与边界行为:
- 数值运算关注精度与类型:除法
/结果恒为float;负数整除//向负无穷取整。 - 逻辑运算善用短路机制:
and遇假即止,or遇真即止;返回对象本身而非单一布尔值,适合构建默认值兜底和安全访问链。 - 比较区分值与引用:普通数值、字符串、列表等内容比对永远用
==;检查单例None时严格使用is None。 - 成员检索甄选数据结构:对高频包含判定场景,优先将列表转换为
set或dict,将O(n)降为O(1)。 - 代码清晰度优先:遇到复合表达式时,合理使用括号
(),用清晰的语义表达业务逻辑。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













