在迭代切片时避免创建新列表的Pythonic方法?

在迭代切片时避免创建新列表的Pythonic方法?,python,python-2.x,Python,Python 2.x,非常常见的模式是浏览列表的一部分并搜索/选择/处理项目: for item in array[start:end]: # do something 据我所知,这将从复制项的数组[start:end]创建一个新列表,遍历它,然后临时列表被垃圾收集。这看起来像是对CPU使用的浪费 使用解决这个问题 问:为什么这没有被大量使用,并且像被教授可变默认函数参数的危险等一样 更新: 正如评论中所指出的,itertools.islice是用于iterables的,而不是列表。在到达第n个元素之前,它必

非常常见的模式是浏览列表的一部分并搜索/选择/处理项目:

for item in array[start:end]:
   # do something
据我所知,这将从复制项的数组[start:end]创建一个新列表,遍历它,然后临时列表被垃圾收集。这看起来像是对CPU使用的浪费

使用解决这个问题

问:为什么这没有被大量使用,并且像被教授可变默认函数参数的危险等一样

更新:

正如评论中所指出的,itertools.islice是用于iterables的,而不是列表。在到达第n个元素之前,它必须迭代很多次

我想islice不是一个好例子,但是创建一个临时列表只是为了浏览它是一个存在的问题。不是吗

你可以做:

for i in xrange(start, end):
    item = array[i]
    # do something with the item

有没有一种pythonic方法可以在不创建序列副本的情况下迭代序列的一部分?。因为本例中不支持负索引,而且它不如按顺序显示项好。

切片之所以是Pythonic的,即使它创建了一个副本,是因为切片的成本在总体方案中通常是微不足道的。如果您从列表中分割10000个项目,只是为了迭代并丢弃它们,那么这样做的成本是:

为10000个指针分配40K-80K字节的空间 将指针从源复制到新空间 递增每个指针的引用计数 在这里使用内容 递减每个指针的引用计数 释放空间 在C级,相对于解释器本身的开销而言,分配几KB的RAM和增加/减少几千个整数是非常简单的。请记住,无论您做什么,当您循环并将每个元素存储在命名变量中时,引用计数都会更新;使用结果列表所做的任何事情都将比创建和销毁它的成本更高,特别是当切片很小时,可能替换它的任何东西的解释器开销都超过了切片的成本

如果拷贝确实是一个问题,并且开始索引非常重要,因此islice无法直接跳到开始点,这使得它不可行,并且切片足够大,您有理由担心内存问题,那么我所知道的最具python风格的方法基本上就是您提供的示例循环:

for i in xrange(start, end):
    item = array[i]
    # do something with the item
如果这太慢,重复索引会在CPython引用解释器中产生惊人的解释器开销,那么最具python风格的替代方法就是将索引推送到C层:

from future_builtins import map  # Only needed on Python 2 to get Py3 generator based map

for item in map(array.__getitem__, xrange(start, end)):  # range on Python 3
    # do something with the item

这避免了临时列表,以换取更高的每元素成本,因为索引无法完全避免,只是隐藏在C层,不涉及字节码执行。虽然map通常不受欢迎,但绝对不太像Pythonic,而且对特殊方法(如u getitem uu)的显式引用特别难看。

大概是因为只有在性能成为问题时,才会有这种程度的理解。当您的代码刚刚运行时,可以说切片行为很好。itertools.islice是用于iterables的,而不是列表。在到达第n个元素之前,它必须迭代多次。您可能对这个问题感兴趣,但它不适合堆栈交换Q&a格式。艾利斯岛的权衡并非完全是黑白的;例如,使用复制的索引创建一个新的列表对象可能比必须首先迭代开始条目以获得所需的切片要快。也许islice不是一个好例子,但是创建一个临时列表只是为了遍历它是一个存在的问题。还有其他选择吗?欢迎您加入我们的讨论会,讨论这类问题;我想知道为什么在互动环境中提问效果更好。