Python: 遍历 'list[a:b]' 是否会先复制该部分列表(可能代价高)?

6 投票
3 回答
7768 浏览
提问于 2025-04-17 08:47

当我从 list1 中的 startstop 进行遍历时,就像这样:

for value in list1[start:stop]:
    ....

那么,Python 是不是会先复制那部分列表(就像执行 list2 = list1[:] 时那样)?如果列表很大,这样做可能会非常耗费资源!

如果在上面的例子中它没有复制,那这种情况总是这样吗?我需要在很大的(非常大的)列表的某些部分上,频繁地执行以下类型的循环:

for index, value in enumerate(list1[start:stop], start):
    ....

3 个回答

1

与其问这个问题,你不如试试神奇的ID方法。

>>> x=[1,2,3,4]
>>> id(x[1])   
4971620
>>> id(x[1:][0]) #same as the original list
4971620
>>> id(x[2:3])
44327400
>>> id(x)
44408224
>>> 

x[2:3] 实际上是创建了一个新列表,但这些元素仍然指向原来的列表。

2

是的。

这个表达式 list1[start:stop] 会创建一个新的列表,里面包含了指定范围内的元素。不过,它并不是在复制实际的数据,而是复制了一些指向这些数据的指针。所以,除非列表非常长,否则这种额外的开销通常不会影响太大。

8

list1[start:stop] 这个操作会创建一个新的列表,没错。这种情况总是如此,不管你是直接遍历这个结果,还是在中间加了个函数,或者在其他任何地方使用它(如果你用的是一种比较静态的语言,或者有复杂的类型推断,才能在简单的情况下优化这个操作)。

要注意的是,这个操作与遍历是无关的!遍历本身并不会复制,而列表切片操作即使你把结果丢掉了也会进行复制。

不过,它只复制了指针,所以如果你每次取的子列表都很小,你可能不会注意到有什么不同。如果子列表比较大,你可以选择遍历索引([x]range)或者使用 itertools.islice。不过,后者在开始时需要跳过 start 个项目,所以为了节省内存,你可能会付出较大的时间成本。前者虽然看起来不太好,但在效率上是最好的,尤其是当数据量很大时。

撰写回答