Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python中切片列表而不生成副本_Python_List_Slice - Fatal编程技术网

在Python中切片列表而不生成副本

在Python中切片列表而不生成副本,python,list,slice,Python,List,Slice,我有以下问题 给定一个整数列表L,我需要为[0,len(L)-1],中的k生成所有子列表L[k:,,而不生成副本 如何在Python中实现这一点?是否有缓冲区对象?根据您所做的操作,您可能能够使用 由于它是通过迭代进行操作的,因此它不会生成新的列表,而是简单地创建迭代器,根据其范围的要求从原始列表中生成元素。 切片列表不会生成列表中对象的副本;它只是复制对它们的引用。这就是问题的答案 长话短说 对可变和不可变值的测试 首先,让我们测试一下基本的声明。我们可以证明,即使在不可变对象(如整数)的情况

我有以下问题

给定一个整数列表
L
,我需要为[0,len(L)-1],中的k生成所有子列表
L[k:
,而不生成副本


如何在Python中实现这一点?是否有缓冲区对象?

根据您所做的操作,您可能能够使用

由于它是通过迭代进行操作的,因此它不会生成新的列表,而是简单地创建迭代器,
根据其范围的要求从原始列表中生成元素。
切片列表不会生成列表中对象的副本;它只是复制对它们的引用。这就是问题的答案

长话短说 对可变和不可变值的测试 首先,让我们测试一下基本的声明。我们可以证明,即使在不可变对象(如整数)的情况下,也只复制引用。以下是三个不同的整数对象,每个对象的值相同:

>>> a = [1000 + 1, 1000 + 1, 1000 + 1]
它们具有相同的值,但您可以看到它们是三个不同的对象,因为它们具有不同的
id
s:

>>> map(id, a)
[140502922988976, 140502922988952, 140502922988928]
切片时,引用保持不变。未创建任何新对象:

>>> b = a[1:3]
>>> map(id, b)
[140502922988952, 140502922988928]
使用具有相同值的不同对象表明,复制过程并不麻烦——它只是直接复制引用

使用可变值进行测试会得到相同的结果:

>>> a = [{0: 'zero', 1: 'one'}, ['foo', 'bar']]
>>> map(id, a)
[4380777000, 4380712040]
>>> map(id, a[1:]
... )
[4380712040]
检查剩余内存开销 当然,引用本身是复制的。在64位机器上,每台机器的成本为8字节。每个列表都有72字节的内存开销:

>>> for i in range(len(a)):
...     x = a[:i]
...     print('len: {}'.format(len(x)))
...     print('size: {}'.format(sys.getsizeof(x)))
... 
len: 0
size: 72
len: 1
size: 80
len: 2
size: 88
正如乔·皮索诺(Joe Pinsonault)所言,这一开销加起来了。整数对象本身并不是很大——它们比引用大三倍。因此,这在绝对意义上为您节省了一些内存,但渐进地说,能够在同一内存中包含多个“视图”列表可能会更好

使用视图节省内存 不幸的是,Python没有提供简单的方法来生成列表中的“视图”对象。或者我应该说“幸运”!这意味着你不必担心切片来自哪里;对原始的更改不会影响切片。总的来说,这使得关于程序行为的推理更加容易

如果您确实想通过使用视图来保存内存,请考虑使用<代码> NoMPy < /Cord>数组。当您对

numpy
数组进行切片时,切片和原始数组之间共享内存:

>>> a = numpy.arange(3)
>>> a
array([0, 1, 2])
>>> b = a[1:3]
>>> b
array([1, 2])
当我们修改
a
并再次查看
b
时会发生什么

>>> a[2] = 1001
>>> b
array([   1, 1001])
但这意味着您必须确保在修改一个对象时,不会无意中修改另一个对象。当你使用
numpy
时,这是一种折衷:减少计算机的工作量,增加程序员的工作量

一个简单的替代方案,它不需要遍历不需要的列表项:

def listslice(xs, *args):
    for i in range(len(xs))[slice(*args)]:
        yield xs[i]
用法:

>>> xs = [0, 2, 4, 6, 8, 10]

>>> for x in listslice(xs, 2, 4):
...     print(x)
4
6

我编写了一个
ListView
类,它甚至避免复制列表的脊椎:

这支持嵌套切片,以便可以继续切片到视图中以获得更窄的视图。例如:
ListView(列表(范围(10))[4:[2:[1]==7


请注意,这不是完全烘焙的,当底层列表随测试套件一起发生变化时,应该进行更多的错误检查。

通常,列表切片是最好的选择

下面是一个快速性能比较:

from timeit import timeit
from itertools import islice

for size in (10**4, 10**5, 10**6):
    L = list(range(size))
    S = size // 2
    def sum_slice(): return sum(L[S:])
    def sum_islice(): return sum(islice(L, S, None))
    def sum_for(): return sum(L[i] for i in range(S, len(L)))

    assert sum_slice() == sum_islice()
    assert sum_slice() == sum_for()

    for method in (sum_slice, sum_islice, sum_for):
        print(f'Size={size}, method={method.__name__}, time={timeit(method, number=1000)} ms')
结果:

Size=10000,   method=sum_slice,  time=0.0298 ms
Size=10000,   method=sum_islice, time=0.0449 ms
Size=10000,   method=sum_for,    time=0.2500 ms
Size=100000,  method=sum_slice,  time=0.3262 ms
Size=100000,  method=sum_islice, time=0.4492 ms
Size=100000,  method=sum_for,    time=2.4849 ms
Size=1000000, method=sum_slice,  time=5.4092 ms
Size=1000000, method=sum_islice, time=5.1139 ms
Size=1000000, method=sum_for,    time=26.198 ms

您是不想复制列表本身,还是不想复制列表中的对象?我不想在生成切片时复制列表中的对象。默认情况下,Python不复制。您如何知道正在创建副本?您注意到资源增加了吗?在不可变对象(如元组)中,引用是不可变的,但它们引用的项可以是可变的。因此,一个由3个列表组成的元组是不能更改的,它将始终引用相同的3个列表,但每个列表的内容都可以更改,就像在任何列表中一样。虽然答案是正确的,但该示例并没有实际演示它,因为小整数被插入;尝试执行
id(2)
甚至
id(1+1)
。一个更好的例子是使用
A=[]、[]、[]、[]]
。或者,在进一步阅读之后,这个问题实际上指定列表由整数组成,因此我觉得很奇怪,作者甚至开始担心项目副本!(我宁愿认为OP没有完全理解您的澄清请求,实际上是想在原始列表中获得“视图”)这个答案是正确的,但我认为值得指出的是,如果您有非常大的arrays@ExpHP,这可能是真的。我尽量不长篇大论,但我想这样的问题是不可能的!这里的缺点是islice没有利用实现getitem方法的对象,将所有内容都视为迭代器,因此它将始终从列表的第一个元素开始迭代,直到到达列表的第一个位置,开始生成范围内的值。