
Python中对列表使用+=会就地扩展原列表、保持对象身份不变;而+则创建全新列表对象,原列表不受影响——这是由底层__iadd__与__add__方法实现机制决定的关键差异。
python中对列表使用`+=`会就地扩展原列表、保持对象身份不变;而`+`则创建全新列表对象,原列表不受影响——这是由底层`__iadd__`与`__add__`方法实现机制决定的关键差异。
在Python中,看似相似的 += 和 + 运算符在操作列表时行为截然不同,其根本原因在于它们调用的是两个完全独立的特殊方法:+= 触发 __iadd__()(in-place add),而 + 调用 __add__()(regular add)。理解这一机制,是写出高效、可预测代码的关键。
✅ +=:就地修改,对象身份不变
+= 是就地增强赋值(in-place augmented assignment),对可变序列(如 list)而言,它直接在原对象内存地址上追加元素,不创建新对象。这等价于调用 list.extend():
x = [1, 2] y = x # y 与 x 指向同一列表对象 x += [3, 4] print(x) # [1, 2, 3, 4] print(y) # [1, 2, 3, 4] —— 仍与 x 相同 print(x is y) # True —— 内存地址未变
通过 id() 可验证其“原地性”:
a = [1, 2] print(id(a)) # 例如:140234567890123 a += [3] print(id(a)) # 仍是:140234567890123 → 地址不变
? 底层原理:list.__iadd__() 方法直接调用 CPython 的 list_extend() 实现,复用原有内存块(必要时扩容),避免复制开销。
立即学习“Python免费学习笔记(深入)”;
❌ +:新建对象,切断引用链
+ 运算符执行的是纯函数式拼接:它始终返回一个全新列表,原始列表保持不变。其行为等价于 list1 + list2 → [*list1, *list2]:
x = [1, 2] y = x x = x + [3] # 创建新列表并重新绑定 x print(x) # [1, 2, 3] print(y) # [1, 2] —— y 仍指向旧对象 print(x is y) # False —— 对象已不同
同样用 id() 验证:
a = [1, 2] print(id(a)) # 140234567890123 b = a + [3] print(id(a)) # 140234567890123 → 原对象未变 print(id(b)) # 140234567890456 → 全新地址
⚠️ 注意:+ 要求右侧操作数必须是 list 类型(或严格支持 __add__ 的同类序列),而 +=/extend() 只要求右侧是任意可迭代对象(如 tuple, set, range):
lst = [1, 2] lst += (3, 4) # ✅ 合法:元组被逐项添加 # lst = lst + (3, 4) # ❌ TypeError:list 与 tuple 不支持 + 拼接
? 字节码印证:BINARY_OP 13 (+=) vs BINARY_OP 0 (+)
正如 dis 输出所示:
- += 编译为 BINARY_OP 13,触发 __iadd__,执行原地修改;
- + 编译为 BINARY_OP 0,触发 __add__,构造并返回新对象。
这意味着:
? 性能上:+= 时间复杂度接近 O(k)(k 为待添加元素数),空间复杂度 O(1)(无额外分配);
? + 则需 O(n+k) 时间(复制两列表)和 O(n+k) 空间,在大数据量场景下显著更慢、更耗内存。
? 常见陷阱与最佳实践
-
别在循环中滥用 + 拼接列表:
# ❌ 低效:每次迭代都新建列表,O(n²) 复杂度 result = [] for item in data: result = result + [item] # ✅ 推荐:用 `+=` 或 `append()` / `extend()` result = [] for item in data: result += [item] # 或 result.append(item) 注意 += 对不可变类型(如 tuple, str)的行为:
它们没有 __iadd__,故 += 会退化为 +(即新建对象),此时 += 与 + 效果一致。警惕嵌套可变对象的副作用:
若列表包含可变对象(如子列表),+= 修改原列表的同时,所有引用该列表的变量都会看到变化——这是设计使然,非 bug。
✅ 总结对比表
| 特性 | list1 += list2 | list1 = list1 + list2 |
|---|---|---|
| 是否修改原对象 | ✅ 是(就地) | ❌ 否(新建) |
| 对象身份(is)是否保留 | ✅ 是 | ❌ 否 |
| 时间复杂度 | O(len(list2)) | O(len(list1)+len(list2)) |
| 内存开销 | 低(可能扩容) | 高(需分配新内存) |
| 右侧类型要求 | 任意可迭代对象 | 必须为 list(或同类序列) |
| 等价方法 | list1.extend(list2) | list1.__add__(list2) |
掌握这一差异,不仅能避免隐蔽的引用错误,更能写出内存友好、性能优越的 Python 列表操作代码。


















