Python 切片列表时是否复制对对象的引用?

Does Python copy references to objects when slicing a list?

当一个列表被切片时,对其内容的引用是否从原始列表中复制?我可以想象这可能没有必要,但我读到了相反的内容(mentioned in passing)。

这个问题很重要,例如下面的成语,在很长的情况下 my_list:

for (first_elmt, second_elmt) in itertools.izip(my_list[:-1], my_list[1:]):
    …

副本会耗尽内存,而且可能会耗费一些时间。我将 first_elmt 的索引与 xrange() 的索引进行了比较,在一个包含 1 亿个整数的列表中。切片方法实际上快了 20%,但似乎确实复制了引用(系统时间更长)。真的是这样吗?

PS:我现在意识到切片复制引用是很自然的:如果原始列表被修改,切片不会改变,所以它更容易实现切片复制原始列表的引用。不过,指向 CPython 实现的指针会很有趣。

切片将复制引用。如果你有一亿个东西的清单:

l = [object() for i in xrange(100000000)]

然后你切一片:

l2 = l[:-1]

l2 将拥有自己的 99,999,999 个指针的支持数组,而不是共享 l 的数组。然而,这些指针指向的对象没有被复制:

>>> l2[0] is l[0]
True

如果您想在不复制的情况下迭代列表中的重叠元素对,您可以zip 列表中的迭代器已经前进了一个位置:

second_items = iter(l)
next(second_items, None) # Avoid exception on empty input
for thing1, thing2 in itertools.izip(l, second_items):
    whatever()

这利用了 zip 在任何输入迭代器停止时停止的事实。这可以扩展到您已经使用 itertools.tee

使用迭代器的情况
i1, i2 = itertools.tee(iterator)
next(i2, None)
for thing1, thing2 in itertools.izip(i1, i2):
    whatever()

是的,slicing DO copy references,事实上,以这种方式复制列表是一个成语:newlst = lst[:].