列表的 += 调用 iadd 实现原地修改,而 + 调用 add 返回新列表;不可变类型因无 __iadd__,+= 退化为 + 赋值;右操作数只需可迭代,不强制为 list 类型。

列表的 += 调用的是 __iadd__,不是 __add__
Python 中所有运算符背后都对应特殊方法:+ 查找 __add__,+= 优先查找 __iadd__。列表类实现了 __iadd__,它直接在原对象上做 extend() 操作;而 __add__ 总是返回新列表。
这导致行为差异的根本原因不是“语法糖”,而是底层方法实现策略不同:
-
a = a + b:调用a.__add__(b)→ 返回新列表 →a指向新地址 -
a += b:调用a.__iadd__(b)→ 原地修改a→id(a)不变
不可变对象(如 int、str)的 += 实际也是新建对象
整数、字符串没有 __iadd__ 方法,所以 += 会退化为 __add__ + 赋值。例如:
x = 5 print(id(x)) # 例如 140...208 x += 3 print(id(x)) # 例如 140...232 —— 地址变了
这说明 += 并不等于“一定原地修改”,它只在对象支持 __iadd__ 时才真正就地操作。可变序列(list、bytearray)支持,不可变类型(int、str、tuple)不支持。
常见误判点:
- 看到
list += ...不报错,就以为所有类型都一样 - 误以为
+=是“语法缩写”,忽略了方法分发机制 - 对元组使用
+=且内部含列表时,会触发TypeError: 'tuple' object does not support item assignment—— 因为元组本身不可变,但__iadd__尝试修改其子项
性能与副作用差异直接影响实际代码逻辑
当多个变量引用同一个列表时,+= 的原地性会引发隐式共享变更:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
a = [1, 2, 3] b = a a += [4] print(b) # [1, 2, 3, 4] —— b 也被改了
而 + 完全不会影响其他引用:
a = [1, 2, 3] b = a a = a + [4] print(b) # [1, 2, 3] —— b 不变
因此关键判断点在于:
- 是否需要保留原始列表结构?选
+ - 是否在意内存分配开销(尤其大列表循环拼接)?选
+=或extend() - 是否在函数内修改传入的列表参数并希望调用方感知?必须用
+=或extend(),不能用+
容易被忽略的兼容性陷阱:右操作数不必是 list
+= 对列表而言,右侧只要可迭代就行,不要求是 list 类型:
nums = [1, 2]
nums += (3, 4) # ✅ 元组,等效于 extend((3, 4))
nums += "ab" # ✅ 字符串,等效于 extend(['a', 'b'])
nums += {5, 6} # ✅ 集合(无序),等效于 extend({5, 6})
但 + 严格要求类型一致:
-
[1] + (2,)→TypeError -
[1] + "2"→TypeError -
[1] + {2}→TypeError
这个灵活性常被当成“便利”,但要注意集合无序、字符串拆成字符等副作用——它们不是 bug,而是 extend() 的固有行为。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










