Python列表底层是动态数组,扩容均摊O(1)但频繁append有开销;copy()与[:]均为浅拷贝;in查找为O(n),应依场景换用set、dict或bisect;del/pop/remove删除成本各异,末尾操作最快。

这个标题本身是个信号——它不指向真实问题,而是典型的内容农场式包装。Python 列表没有“第562讲”,也没有官方“系统学习路线”编号。真正需要的,是厘清 list 在内存中怎么存、在代码里怎么用、在哪些地方会悄悄出错。
为什么 list.append() 是 O(1) 但有时会变慢?
因为底层用动态数组实现:空间不够时,Python 会申请一块更大的连续内存(通常是当前容量的 1.125 倍),再把旧元素逐个拷贝过去。这个扩容动作是 O(n),但均摊下来仍是 O(1)。
- 频繁在循环里
append()大量元素时,实际性能取决于扩容次数,不是调用次数 - 如果预知最终长度,用
[None] * n初始化再按索引赋值,比反复append()更稳 -
sys.getsizeof([])返回 56 字节(CPython 3.12),这是空列表对象本身的开销,不含元素存储空间
list.copy() 和 list[:] 都是浅拷贝,但行为有细微差别
两者都创建新列表对象,但内部元素引用不变。区别在于可读性和兼容性:
-
lst.copy()是 Python 3.3+ 引入的明确方法,语义清晰,推荐用于新项目 -
lst[:]依赖切片语法,在旧代码或需要同时支持 tuple/list 的场景更灵活,但易被误读为“取前几项” - 二者都不解决嵌套结构问题:
original = [[1, 2], [3]] shallow = original.copy() shallow[0].append(99) # original[0] 也会变成 [1, 2, 99]
用 in 查找元素时,时间复杂度是 O(n),别把它当哈希表用
list 没有索引结构,item in my_list 就是顺序扫描。高频查找请换数据结构:
立即学习“Python免费学习笔记(深入)”;
- 改用
set:查找平均 O(1),但失去顺序和重复元素 - 若需保持插入顺序且查得快,用
dict.fromkeys(my_list).keys()(Python 3.7+ 保证有序) - 对已排序列表,可用
bisect模块做二分查找,O(log n),但前提是自己维护有序性
del lst[i]、lst.pop(i)、lst.remove(x) 的成本差异
三者都涉及元素搬移,但触发条件不同:
-
del lst[i]和lst.pop(i)都要移动索引i后面所有元素,时间复杂度 O(n−i);pop()还多一次返回值操作 -
lst.remove(x)先从头遍历找第一个匹配项(O(n)),再执行删除(O(n−i)),最坏 O(2n) - 删末尾最快:
pop()或del lst[-1]是真正的 O(1),无需搬移
列表不是万能容器。它的优势在随机访问和尾部操作,劣势在中间插入/删除、成员存在性检查、去重、排序后查找。用错场景比写错语法更容易拖垮程序——尤其当 list 装了上万条日志或用户 ID 时。










