一、切片:[start:stop:step]
a = [0, 1, 2, 3, 4, 5]
a[1:4] # [1, 2, 3] 左闭右开
a[:3] # [0, 1, 2]
a[-2:] # [4, 5] 最后两个
a[::2] # [0, 2, 4] 步长 2
a[::-1] # [5, 4, 3, 2, 1, 0] 反转
要点:
- 左闭右开,
a[1:4]不含索引 4。 - 越界不报错,
a[1:100]会返回能取到的部分;但索引访问a[100]会IndexError。 - 切片返回新列表,是浅拷贝。
a[::-1]反转比a.reverse()多一次内存分配,但不会改原列表。
二、b = a 不是复制
a = [1, 2, 3]
b = a
b.append(4)
print(a) # [1, 2, 3, 4] ← a 也变了
b = a 只是让两个名字指向同一个列表对象。要真正复制:
b = a.copy() # 浅拷贝
b = a[:] # 浅拷贝
b = list(a) # 浅拷贝
import copy
b = copy.deepcopy(a) # 深拷贝(嵌套结构也复制)
浅拷贝只复制第一层,嵌套的列表仍是共享的:
a = [[1], [2]]
b = a.copy()
b[0].append(9)
print(a) # [[1, 9], [2]] ← 内层被改
处理嵌套结构必须 deepcopy。
三、列表推导式
squares = [x * x for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
pairs = [(x, y) for x in range(3) for y in range(3)]
比 for 循环 + append 更快、更短。但不要嵌套超过两层,可读性会崩。数据量很大时改用生成器表达式 (x*x for x in ...),省内存。
四、sort 与 sorted
a = [3, 1, 2]
a.sort() # 原地排序,返回 None
b = sorted(a) # 返回新列表
a.sort(reverse=True)
a.sort(key=lambda x: x[1]) # 按第二个元素
a.sort(key=lambda x: (x[1], -x[0])) # 多级排序
两个常见错误:
a = a.sort()→a变成None。- 排序键返回混合类型(既有
int又有str)→TypeError。
sort 是稳定排序,相同键的元素保持原顺序,这对多级排序很有用。
五、遍历时不要删元素
# 错误:删除后索引前移,会跳过元素
for x in lst:
if x < 0:
lst.remove(x)
# 正确:用推导式生成新列表
lst = [x for x in lst if x >= 0]
# 或倒序遍历
for i in range(len(lst) - 1, -1, -1):
if lst[i] < 0:
del lst[i]
同样的问题也出现在 for i in range(len(lst)) 里 pop。修改列表结构时不要同时遍历它,这是通用原则。
六、常用操作速查
lst.append(x) # 尾部加一个
lst.extend([1, 2]) # 尾部加多个
lst.insert(0, x) # 指定位置插入(O(n),慎用)
lst.pop() # 弹出尾部
lst.pop(0) # 弹出头部(O(n))
lst.remove(x) # 删除第一个值为 x 的元素,不存在报错
lst.index(x) # 找索引,不存在报错
lst.count(x) # 计数
x in lst # 成员判断(O(n))
lst.clear() # 清空
频繁在头部增删应该用 collections.deque,list 的头部操作是 O(n)。
七、性能与选择
- 成员判断频繁 → 用
set(O(1))。 - 需要键值对 → 用
dict。 - 固定长度、大量数值计算 → 用
array或 NumPy。 - 队列 →
deque。
list 适合「有序、可变、随机访问」的场景,别拿它当万能容器。
小结
b = a 是引用、a.copy() 才是浅拷贝、嵌套用 deepcopy;sort 原地改、sorted 返回新的;遍历时别删元素,用推导式重建;头部操作换 deque。