Python赋值运算符+=、-=等复合写法怎么用?

云舒
云舒
发布时间:2026-10-27| 4人浏览过
原创
在 Python 中,+=、-= 等复合赋值运算符(也称增强赋值运算符,Augmented Assignment Operators)通过将算术或逻辑运算与变量重新赋值融为一体,能有效简化代码结构。理解复合赋值不仅要掌握基础语法对应关系,更要掌握右侧表达式优先计算规则,以及可变对象与不可变对象在底层内存机制中的本质差异。

一、什么是复合赋值运算符与语法映射

复合赋值运算符是常规二元运算与赋值操作的紧凑结合形式。在基础数值场景下,x += 1 在行为上直观等价于 x = x + 1。这种简写消除了重复编写变量名的繁琐,同时降低了代码中变量拼写错误的几率。

Python 支持全部标准的二元算术运算与位运算对应的复合形式,常见符号及其功能对照如下:

复合运算符 典型写法 等价展开表达 运算含义
+= a += b a = a + b 加法赋值(或序列拼接)
-= a -= b a = a - b 减法赋值
*= a *= b a = a * b 乘法赋值(或序列重复)
/= a /= b a = a / b 真除法赋值(结果为浮点数)
//= a //= b a = a // b 整除赋值(向下取整)
%= a %= b a = a % b 取模(求余)赋值
**= a **= b a = a ** b 幂运算赋值
&=, |=, ^= a &= b a = a & b 按位与、按位或、按位异或赋值
<<=, >>= a <<= b a = a << b 位左移、位右移赋值

下面是一个基础数值计算的演示示例:

# 基础数值复合赋值示例
count = 10
count += 5     # 相当于 count = count + 5,结果 15
count -= 3     # 相当于 count = count - 3,结果 12
count *= 2     # 相当于 count = count * 2,结果 24
count /= 4     # 相当于 count = count / 4,结果 6.0(浮点数)
count //= 2    # 相当于 count = count // 2,结果 3.0
count **= 3    # 相当于 count = count ** 3,结果 27.0
print("最终计算结果:", count)  # 输出: 最终计算结果: 27.0
Python赋值运算符+=、-=等复合写法怎么用?
图 1:Python 复合赋值运算符底层优先评估右侧,并根据类型支持调用就地方法或常规方法

二、核心机制:可变对象与不可变对象的底层差异

初学者最容易产生误解的地方,是将 a += b 简单理解为 a = a + b 的纯粹语法糖。在处理不可变类型(如 int、float、str、tuple)时,两者的表现确实一致;但当操作对象为可变类型(如 list、dict、set)时,底层运作机制存在根本不同。

1. 不可变对象的内存行为

以整数或字符串为例,它们的值一旦创建便不可更改。执行 num += 1 时,Python 无法修改原有整数对象,而是通过 __add__ 运算在内存中创建一个全新的整数对象,并将变量名 num 指向这个新地址。

# 不可变对象的复合赋值示例
x = 100
print("运算前地址:", id(x))

x += 1
print("运算后地址:", id(x))  # 内存地址发生改变,说明生成了新对象

2. 可变对象的就地修改(In-place)

对于列表等可变对象,+= 会优先调用内置的 __iadd__ 方法,执行就地修改(In-place Modification)。这类似于直接调用 list.extend(),原列表的内存地址保持不变。

反之,如果显式书写 list_a = list_a + list_b,则始终会调用常规的 __add__ 方法,强制在内存中新建一个列表,并将 list_a 重新绑定。

# 可变对象对比示例
# 方式 A:使用复合赋值 +=
list_one = [1, 2]
print("list_one 运算前:", id(list_one))
list_one += [3]
print("list_one 运算后:", id(list_one))  # 地址完全相同,就地扩充

# 方式 B:使用普通加法重新赋值
list_two = [1, 2]
print("list_two 运算前:", id(list_two))
list_two = list_two + [3]
print("list_two 运算后:", id(list_two))  # 地址发生改变,新建了列表对象
多变量共享引用的副作用: 当多个变量引用同一个可变对象时,+= 的就地修改会同步影响所有引用该对象的变量;而普通 list = list + [...] 则会解除共享引用。
# 共享引用下的行为差异
a = [10, 20]
b = a          # b 和 a 指向同一个列表

a += [30]      # 就地修改原列表
print("a:", a)  # 输出: [10, 20, 30]
print("b:", b)  # 输出: [10, 20, 30](b 也被同步改变了!)

# 对比普通加法
c = [10, 20]
d = c
c = c + [30]   # c 指向了新建的列表,d 仍停留在原列表
print("c:", c)  # 输出: [10, 20, 30]
print("d:", d)  # 输出: [10, 20](d 未受影响)
Python赋值运算符+=、-=等复合写法怎么用?
图 2:不可变对象通过生成新实例并重定向变量完成赋值,而可变对象则在原内存块直接就地修改

三、经典边界陷阱:元组嵌套列表复合赋值的异常冲突

Python 社区中有一个著名的经典面试题与易错陷阱:如果一个不可变元组(tuple)内部包含了一个可变列表(list),对其进行 += 操作会发生什么?

# 元组内列表复合赋值测试
t = ([1, 2], "hello")

try:
    t[0] += [3]
except TypeError as err:
    print("捕获到异常:", err)

print("最终 t 的内容:", t)

运行这段代码后,会得到令人惊讶的双重现象:

  1. 程序抛出了异常:TypeError: 'tuple' object does not support item assignment(元组不支持元素项赋值)。
  2. 查看 t[0] 的实际内容,却发现列表成功变成了 [1, 2, 3]!

这一看似矛盾的现象,正是因为复合赋值 t[0] += [3] 分解为两个相对独立的底层动作:

  • 阶段一(就地求值): Python 取出 t[0],获取其指向的底层列表对象,并执行 __iadd__([3])。列表对象原地追加成功,并返回列表自身引用。
  • 阶段二(写回赋值): 复合赋值机制必须执行完整的赋值闭环,即 t[0] = result。由于 t 是元组,元组严格禁止任何对其项的赋值操作,因而引发 TypeError。
Python赋值运算符+=、-=等复合写法怎么用?
图 3:元组嵌套列表复合赋值发生冲突的实质:运算阶段成功与赋值阶段受阻分离

四、复合赋值运算符的求值顺序与优先级

在书写较为复杂的复合赋值表达式时,必须谨记一条铁律:复合赋值运算符右侧的所有表达式,会作为一个整体优先求值,最后才执行复合赋值运算。

许多初学者在遇到 x *= y + 2 时,会误以为它等同于 x = x * y + 2。实际上,它严格等价于 x = x * (y + 2)。

# 求值顺序验证
x = 5
y = 3

# 错误直觉:5 * 3 + 2 = 17
# 实际行为:5 * (3 + 2) = 25
x *= y + 2
print("x 的实际计算值:", x)  # 输出: 25

其原因在于:赋值运算符(包括所有复合赋值运算符)在 Python 运算符优先级表中几乎排在最末位。右侧的加减乘除二元运算具有更高的优先级,必然全部计算出结果值之后,才与左侧变量进行复合运算。

五、最佳实践与编写建议

为了保证代码的清晰度、性能与可维护性,在实际项目中使用复合赋值运算符时应遵循以下建议:

  • 数值累加与计数器优先使用复合赋值: 在循环中更新索引、计数器或累加和时,i += 1、total += price 更加简洁直观,是 Python 社区公认的标准惯用法。
  • 避免在长循环中对字符串使用 +=: 虽然字符串支持 += 拼接,但因为字符串是不可变对象,每次拼接都会复制旧字符并分配新内存,产生 $O(N^2)$ 的时间开销。大批量字符拼接应使用 "".join(str_list)。
  • 留意列表别名的副作用: 如果一个列表被传递给函数或赋给了多个变量,使用 lst += [item] 会就地修改该列表,影响调用方的数据;若不希望影响外部引用,应显式采用 lst = lst + [item] 或传递切片副本 lst[:]。
  • 严禁在不可变容器的元素项上调用复合赋值: 如前文所述,不要在元组内的列表元素上使用 tuple[0] += [x],如果确实需要更新元组内部的列表,应直接调用列表的显式方法:t[0].append(x) 或 t[0].extend([x]),从而规避无意义的写回赋值异常。
Python赋值运算符+=、-=等复合写法怎么用?
图 4:Python 复合赋值运算符选用决策与核心最佳实践汇总

六、总结

Python 的复合赋值运算符(+=、-=、*= 等)远不止是输入时的“偷懒”简写。掌握其使用方法应重点把握以下三个层次:

  1. 表达层次: 熟练运用 +=、-= 等运算符简化代码,同时牢记右侧表达式整体优先计算的优先级规则。
  2. 机制层次: 理解不可变类型通过新建对象并重新绑定变量实现运算,而可变类型则通过 __iadd__ 等魔术方法执行高性能的原址就地修改。
  3. 安全层次: 警惕多变量共享引用时的连带改动,并规避元组等不可变容器内嵌套可变对象时的复合赋值陷阱。
相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。