切片操作总是返回新对象,不可避免内存拷贝;真正零拷贝仅通过memoryview实现,itertools.islice适合惰性遍历,list切片优化应优先使用del原地删除。

切片操作本身不避免拷贝,但可控制拷贝范围
Python 中的切片(如 lst[2:5] 或 s[1:-1])**总是返回新对象**,对 list、str、bytes 等内置类型而言,这意味内存拷贝不可避免。所谓“避免不必要的拷贝”,关键不是消灭切片拷贝,而是避免在不需要全部数据时,仍切出大段再丢弃——比如只取前 10 行却切了整个 GB 文件列表。
- 对
list:切片会创建新列表,复制引用(小对象快,大列表内存/时间开销明显) - 对
str:同样新建字符串对象,不可变性决定了无法绕过拷贝 - 对
memoryview或array.array:切片可共享底层缓冲区,真正零拷贝(但需类型支持)
用 memoryview 实现真正零拷贝切片
当你处理的是二进制数据(如从文件读入的 bytes、bytearray 或 NumPy 数组),memoryview 是唯一标准库中能实现切片不拷贝的机制。它只是原始缓冲区的“视图”,切片操作只调整起始偏移和长度。
data = b'hello world' mv = memoryview(data) sub = mv[0:5] # 不拷贝,sub.obj 是 data,sub.nbytes == 5 assert sub.tobytes() == b'hello' # 转 bytes 才触发拷贝
- 仅适用于支持缓冲协议的对象:
bytes、bytearray、array.array、numpy.ndarray等 -
memoryview切片后仍是memoryview,不转成bytes就不分配新内存 - 不能对普通
list或str构造memoryview(会报TypeError: memoryview: a bytes-like object is required)
替代方案:用 itertools.islice 做惰性切片
当目标是“遍历某段子序列”而非“持有全部切片结果”,itertools.islice 是更轻量的选择。它不生成新容器,只按需产出元素,适合流式处理或大迭代器。
from itertools import islice large_range = range(10**9) # 占内存极少 first_5 = list(islice(large_range, 5)) # 只计算前 5 个值 middle_chunk = islice(large_range, 1000, 1010) # 无内存压力
-
islice(iterable, start, stop[, step])返回迭代器,不缓存中间项 - 对非索引型迭代器(如文件行、生成器)尤其有用;但不支持负索引或反向切片
- 若后续还需随机访问,
islice不适用——它是一次性、单向的
list 切片优化:别切完再删,改用 del 或 pop
常见误操作:用 lst = lst[n:] 截掉前 n 项。这会创建新列表并让原列表待回收,对大列表造成双倍内存峰值。更高效的做法是原地修改。
立即学习“Python免费学习笔记(深入)”;
- 截前缀:用
del lst[:n]—— 原地删除,不产生新列表 - 截后缀:用
del lst[-n:]或lst[:] = lst[:-n](后者仍拷贝,但比lst = lst[:-n]少一次名字重绑定) - 需要保留原列表?考虑用
collections.deque,popleft()和pop()都是 O(1)
真正零拷贝只存在于缓冲区视图层面;其余场景所谓“避免拷贝”,本质是减少拷贝量、延迟拷贝时机,或换用更适合的数据结构。别被“切片很轻量”的直觉误导——一个 list[1:1000000] 调用,就是百万级引用的复制动作。


















