相当常见的模式是遍历列表的一部分并搜索/选择/处理项目:
for item in array[start:end]:
# do something
据我所知,这会创建一个新的列表,从array[start:end]
复制项目,遍历它,然后临时列表被垃圾收集。这看起来像是浪费CPU使用率。
使用itertools.islice解决了这个问题。
问题:为什么这个用得不多,而且教会像教了可变默认函数参数的危险等等?
更新
正如评论中所指出的,“itertools.islice
用于迭代,而不是列表。它必须在到达第n个元素之前迭代一堆”。
我猜islice
不是一个很好的例子,但创建一个临时列表只是为了走过它是一个现存的问题。不是吗?
你可以这样做:
for i in xrange(start, end):
item = array[i]
# do something with the item
是否有 pythonic 方法迭代序列的一部分而不创建它的副本?。因为不支持此示例中的负索引,并且它不如for item in sequence
那么好。
答案 0 :(得分:0)
即使创建切片,切片也是Pythonic的原因是,切片的成本通常在宏伟的方案中微不足道。如果您从list
中分割10,000个项目,只是为了对其进行迭代并丢弃它们,则成本为:
在C级别,相对于解释器本身的开销,分配几个KB的RAM和递增/递减的几千个整数是微不足道的(请记住,无论您做什么,都会发生引用计数更新当您循环并将每个元素存储在命名变量中时);使用结果start
进行 几乎比创建和销毁它要昂贵得多,尤其是在切片很小的情况下(其中的解释器开销任何东西,您都可以用替换成本来代替它。
如果副本确实有问题,并且islice
索引很重要(因此start
无法跳至for i in xrange(start, end):
item = array[i]
# do something with the item
点,则直接使其不可行,并且该切片足够大,您可以合理地担心内存),我所知道的最Python化的方法基本上就是您提供的示例循环:
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
如果这太慢了(重复的索引会在CPython参考解释器中带来大量的解释器开销),那么最Python化的选择就是将索引推到C层:
list
这避免了临时的map
,而换来了更高的每个元素成本(因为无法完全避免索引,只是隐藏在C层而没有字节码执行)。不过绝对没有Python风格(__getitem__
常常被人们所皱眉,而对诸如Result <- merge(Employees, Departments, all.x=TRUE)
Result <- Departments[Employees] # same as above
之类的特殊方法的显式引用则非常丑陋)。