如何在列表中获取生成器的n个下一个值(python)

时间:2010-11-11 08:01:13

标签: python list generator

我已经制作了一个生成器来逐字读取文件,它可以很好地工作。

def word_reader(file):
    for line in open(file):
        for p in line.split():
            yield p

reader = word_reader('txtfile')
next(reader)

在列表中获取n个下一个值的最简单方法是什么?

5 个答案:

答案 0 :(得分:47)

使用itertools.islice

list(itertools.islice(it, n))

答案 1 :(得分:11)

编辑:使用itertools.islice。我最初提出的模式是个坏主意 - 当it产生的值小于n时崩溃,这种行为取决于细微的问题,所以阅读这些代码的人不太可能理解它的精确语义。

  

还有

[next(it) for _ in range(n)]
     

对于不熟悉itertools的人来说可能更清楚;但是如果你经常处理迭代器,那么itertools对你的工具集来说是一个有价值的补充。

如果next(it)用尽并且提升StopIteration会怎样?

(即当it的值小于n时)

几年前,当我写上面这一行时,我可能认为StopIteration会产生干净地终止列表理解的聪明副作用。但不,整个理解都会通过StopIteration向上崩溃。 (只有当异常来自range(n)迭代器时才会干净地退出。)

这可能不是你想要的行为。

但它变得更糟。以下应该等同于列表理解(特别是在Python 3上):

list(next(it) for _ in range(n))

不是。内部部分是发电机功能的简写; list()知道在任何地方StopIteration 提升时就已经完成了 =>当没有n值并返回较短列表时,此版本可以安全地处理。 (比如itertools.islice()。)

[执行于:2.73.4]

但这也会改变!当一个生成器StopIteration中的任何代码引发RuntimeError时,生成器默默地退出的事实是一个已知的疣,由PEP 479解决。从Python 3.7(或将来导入的3.5)将导致{{1}}而不是干净地完成生成器。即它会变得类似于列表理解的行为。 (在最近的HEAD版本中测试过)

答案 2 :(得分:3)

for word, i in zip(word_reader(file), xrange(n)):
    ...

答案 3 :(得分:2)

要获取生成器的前n个值,可以使用more_itertools.take

如果您计划迭代块中的单词(例如,一次100个),您可以使用more_itertools.chunked(https://more-itertools.readthedocs.io/en/latest/api.html):

import more_itertools
for words in more_itertools.chunked(reader, n=100):
    # process 100 words

答案 4 :(得分:0)

使用cytoolz.take

>>> from cytoolz import take
>>> list(take(2, [10, 20, 30, 40, 50]))
[10, 20]