gpt4 book ai didi

python - 生成器函数中的 itertools.takewhile - 为什么只评估一次?

转载 作者:太空狗 更新时间:2023-10-29 18:13:34 24 4
gpt4 key购买 nike

我有一个这样的文本文件:

11
2
3
4

11

111

使用 Python 2.7,我想将其转换为行列表列表,其中换行符分隔内部列表中的项目,空行分隔外部列表中的项目。像这样:

[["11","2","3","4"],["11"],["111"]]

为此,我编写了一个生成器函数,一旦传递了一个打开的文件对象,它就会一次生成一个内部列表:

def readParag(fileObj):
currentParag = []
for line in fileObj:
stripped = line.rstrip()
if len(stripped) > 0: currentParag.append(stripped)
elif len(currentParag) > 0:
yield currentParag
currentParag = []

效果很好,我可以从列表推导式中调用它,从而产生所需的结果。然而,后来我想到我可以使用 itertools.takewhile 更简洁地做同样的事情(为了将生成器函数重写为生成器表达式,但我们将保留它目前)。这是我尝试过的:

from itertools import takewhile    
def readParag(fileObj):
yield [ln.rstrip() for ln in takewhile(lambda line: line != "\n", fileObj)]

在这种情况下,生成的生成器只产生一个结果(预期的第一个结果,即 ["11","2","3","4"])。我曾希望再次调用它的 next 方法会导致它对文件的其余部分再次计算 takewhile(lambda line: line != "\n", fileObj) ,从而导致它产生另一个列表。但是没有:我得到的是 StopIteration。所以我推测 take while 表达式只在创建生成器对象时被评估一次,而不是每次我调用结果生成器对象的 next 方法时.

这个假设让我想知道如果我再次调用生成器函数会发生什么。结果是它创建了一个新的生成器对象,该对象在向我抛出 StopIteration 之前也产生了一个结果(预期的第二个结果,即 ["11"]) .所以事实上,将它写成一个生成器函数会有效地给出相同的结果,就好像我将它写成一个普通函数并returned列表而不是yielding它一样.

我想我可以通过创建自己的类来代替生成器来解决这个问题(如 John Millikin 对 this question 的回答)。但关键是我希望写一些比我原来的生成器函数(甚至可能是生成器表达式)更简洁的东西。有人可以告诉我我做错了什么,以及如何改正吗?

最佳答案

对于 groupby,您正在尝试做的是一项完美的工作:

from itertools import groupby

def read_parag(filename):
with open(filename) as f:
for k,g in groupby((line.strip() for line in f), bool):
if k:
yield list(g)

这将给出:

>>> list(read_parag('myfile.txt')
[['11', '2', '3', '4'], ['11'], ['111']]

或者在一行中:

[list(g) for k,g in groupby((line.strip() for line in open('myfile.txt')), bool) if k]

关于python - 生成器函数中的 itertools.takewhile - 为什么只评估一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11852579/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com