append() 原地添加单个元素,时间复杂度 O(1);+= 等价于 extend(),要求右侧可迭代,会迭代展开添加。二者均只复制引用、不深拷贝,但语义和错误模式不同。
![list.append() vs list += [x] 在性能与内存拷贝上的细微差别](https://img.php.cn/upload/article/001/242/473/176950416379808.png)
list.append() 是原地添加单个元素,不触发序列解包
list.append() 直接在列表末尾插入一个对象引用,时间复杂度 O(1)(均摊),且不涉及任何拷贝或迭代。它只修改 list 的内部指针数组,扩容时才发生一次内存重分配。
常见误用是把它当批量操作:比如 lst.append([1, 2, 3]) 会把整个列表作为一个元素嵌套进去,而不是展开。这点和 += 完全不同。
实操建议:
- 明确只加一个元素时,优先用
append()—— 语义清晰、开销最小 - 不要用
append()替代extend()或+=来“假装”批量添加 - 如果目标是追加多个值,用
extend()或+= [x, y, z],而非循环调用append()
list += [x] 实际调用 __iadd__,等价于 extend() 而非 append()
+= 对列表不是简单赋值叠加,而是触发 list.__iadd__() 方法,该方法内部行为与 extend() 完全一致:它迭代右侧对象(必须是可迭代的),逐个调用 append()。所以 lst += [x] 和 lst.extend([x]) 行为相同,但比 lst.append([x]) 多一层迭代和类型检查。
关键细节:
-
lst += [x]要求右侧是可迭代对象;[x]是合法的,但lst += x(x 是 int)会报TypeError: 'int' object is not iterable - 虽然语义上像“加一个元素”,但它仍走迭代路径,有微小额外开销(创建迭代器、检查
__iter__) - 和
extend()一样,若右侧很大,+=会预估容量并一次性扩容,比循环append()更高效
性能差异在小数据量下几乎不可测,但语义和错误倾向完全不同
对单个元素,append() 比 += [x] 快约 1.2–1.5×(CPython 3.12 测得,百万次循环差 ~40ms)。但这不是瓶颈点。真正影响开发体验的是错误模式:
- 写
lst += x(x 是 int)→ 立即报错,提示明确 - 写
lst.append([x])→ 不报错,但产生意外嵌套结构,后期引发TypeError或逻辑 bug,更难定位 -
+=支持任意可迭代对象:lst += "ab"会拆成['a', 'b'];append()则把字符串当一个整体
所以选哪个,主要看你要“加一个东西”还是“加一批东西的展开结果”。
内存拷贝层面:两者都不复制元素对象,只复制引用
无论是 append() 还是 += [x],都只是把对象的引用追加到列表的指针数组中,不会对 x 本身做深拷贝或浅拷贝。如果你改了 x 的内容(比如它是 list 或 dict),所有持有该引用的地方都会看到变化。
容易被忽略的一点:
-
+=在扩容时可能触发一次底层内存 realloc,而append()在同样扩容时机也做同样的事 —— 所以二者在内存分配行为上没有本质区别 - 但
+=若右侧是生成器(如lst += (x for x in range(1000))),会强制完全消费并缓存全部元素,可能导致临时内存上升;append()没这问题,因为它根本不接受生成器作为参数











