
Python切片不是简单的“取子序列”,而是一次独立的内存操作:它会创建新对象,复制原始数据(对于可变序列如 list、bytearray),或共享底层数据(对于不可变序列如 str、tuple,在某些实现中可能复用)。
切片总是返回新对象
无论原对象是否可变,切片表达式 s[i:j:k] 总是返回一个**全新对象**,与原对象在内存中完全独立:
- list 切片:分配新列表,逐个拷贝引用(浅拷贝),原 list 改变不影响切片结果,反之亦然;
- str/tuple 切片:返回新字符串或元组,但 CPython 中对 str 常做“interning”或缓冲区视图优化,逻辑上是新对象,物理上可能复用字符内存(不暴露给用户,不可依赖);
- bytes 切片:返回新 bytes 对象,底层字节数据被复制(CPython 3.12+ 对小切片可能延迟复制,但语义仍是值拷贝)。
性能关键:复制开销取决于类型与大小
切片的耗时主要来自两部分:索引计算 + 元素拷贝。影响显著的因素有:
- 序列长度和切片长度:list 切片 O(k),k 是切片元素个数,不是原列表长度;
- 元素类型复杂度:切 list 时只拷贝对象引用(8 字节/个,64 位系统),不深拷贝内容,所以切含大 dict 的 list 很快;
-
不可变类型的优化空间:str 在 CPython 中使用“string interning”和“rope-like”子串视图(内部未公开 API),使得
s[1000:1005]不必拷贝全部字符,但用户看到的行为仍是“新字符串”; -
步长 k ≠ 1 会降低缓存局部性:例如
lst[::2]遍历间隔访问,CPU 缓存命中率下降,比lst[:]略慢,尤其大数据量时。
避免意外复制:何时该用切片,何时该用视图?
Python 标准类型没有“只读视图”(如 NumPy 的 view),但可通过其他方式规避复制:
立即学习“Python免费学习笔记(深入)”;
- 需要只读访问且数据极大 → 考虑
memoryview(支持 bytes/bytearray/buffer 协议):mv = memoryview(b)[100:200]不复制字节,仅创建轻量视图; - 处理文本子串且关心性能 → str 切片本身已高度优化,无需手动替代;
- 频繁切 list 并修改 → 若只是遍历,改用索引迭代(
for i in range(i_start, i_end, step))避免生成中间 list; - 需真正共享数据逻辑 → 显式传递原对象 + 起止索引,或封装为自定义类(如
SubList(lst, start, stop)),而非依赖切片。
验证复制行为的小技巧
用 id() 和 is 只能判断对象身份,不能代替逻辑判断;可靠方式是观测可变性:
- 对 list 切片后修改子列表,原列表不变 → 证明是副本;
- 对 list 中嵌套的 dict 执行
slice[0]['x'] = 1,原 list 对应位置也变 → 说明引用被共享(浅拷贝正常行为); - 用
sys.getsizeof()粗略对比:切大 list 前后内存增长约len(slice) * 8字节(引用大小),而非元素实际体积。











