如何将生成器的下一个值放入列表中

问题描述 投票:0回答:5

我制作了一个生成器来逐字读取文件,效果很好。

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

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

将接下来的 n 个值放入列表的最简单方法是什么?

python list generator
5个回答
100
投票

使用

itertools.islice

list(itertools.islice(it, n))

19
投票

TL;DR:使用

itertools.islice

本来我写了另一个答案,结果证明这是一个坏主意

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

it
产生小于
n
值时,此行为会崩溃,并且此行为取决于微妙的问题,因此阅读此类代码的人不太可能理解其精确的语义。

如果
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
时,生成器会默默退出,这是一个已知的问题,由 PEP 479 解决。从 Python 3.7(或将来导入的 3.5)开始,这将导致
RuntimeError
而不是干净地完成生成器。 IE。它会变得类似于列表理解的行为。 (在最近的 HEAD 版本上进行测试)


4
投票

要获取生成器的前 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
投票
for i, word in zip(range(n), word_reader(file)):
    ...

-1
投票

使用cytoolz.take

>>> from cytoolz import take
>>> list(take(2, [10, 20, 30, 40, 50]))
[10, 20]
© www.soinside.com 2019 - 2024. All rights reserved.