检查并关闭python生成器
我有一段代码,它使用生成器读取两个大文件,当其中一个文件达到EOF时停止。我想知道(1)哪台发电机首先达到EOF,(2)每台发电机的进度,即第一台发电机达到EOF时发电机中检查并关闭python生成器,python,Python,我有一段代码,它使用生成器读取两个大文件,当其中一个文件达到EOF时停止。我想知道(1)哪台发电机首先达到EOF,(2)每台发电机的进度,即第一台发电机达到EOF时发电机中I的值(见下面的代码),以及(3)另一台发电机中剩余的线路数。我不知道提前多久每个文件,并希望避免预扫描的文件 我知道我可以通过以下方式获得进展: 每次调用next()(这太难看了!)时递增一个计数器,或者 让生成器返回一个计数器(请参见代码中的counter1和counter2) 但在这两种情况下,我都不知道是gen1还是g
I
的值(见下面的代码),以及(3)另一台发电机中剩余的线路数。我不知道提前多久每个文件,并希望避免预扫描的文件
我知道我可以通过以下方式获得进展:
next()
(这太难看了!)时递增一个计数器,或者counter1
和counter2
)gen1
还是gen2
达到了EOF
我还发现我可以向StopIteration
异常添加一条“消息”,但我想知道是否有更好的方法。在第一次尝试之后…除了
块之外,我是否可以找出哪一个尚未达到EOF并将其推进?(我尝试在生成器上使用close()
或throw()
,或生成器中的finally
子句,但没有真正理解它们。)
def gen1(fp):
对于i,枚举中的行(fp):
int_val=过程线(线)
收益率区间,i
提升停止迭代(“gen1”,i)
def gen2(fp):
对于i,枚举中的行(fp):
float\u val=过程线某种方式(线)
收益率浮动值,i
提出停止迭代(“gen2”,i)
g1=gen1(打开('large_file','r'))
g2=gen2(打开(“另一个大文件”,“r”))
尝试:
val1,计数器1=下一个(g1)
val2,计数器2=下一个(g2)
进度+=1
虽然正确:#实际代码比这里显示的要复杂一些
而val1>val2:
val2,计数器2=下一个(g2)
而val1
我想您可能想改用它——它是用一个标准Python类实现的,可以有您需要的任何额外属性(例如耗尽的
标志)
如下所示:
# untested
class file_iter():
def __init__(self, file_name):
self.file = open(file_name)
self.counted_lines = 0
self.exhausted = False
def __iter__(self):
return self
def __next__(self):
if self.exhausted:
raise StopIteration
try:
next_line = self.file.readline()
self.counted_lines += 1
return next_line
except EOFError:
self.file.close()
self.exhausted = True
raise StopIteration
您可以使用
chain
将一个特殊的EOF
值固定到生成器的末尾。例如
from itertools import chain
EOF = object()
fin = open('somefile')
src = enumerate(chain(fin, [EOF]))
while True:
idx, row = next(src)
if row == EOF:
break # End of file
print idx, row
您也可以使用izip\u longest
。用生成器替换f1和f2
from itertools import count, izip_longest
EOF = object()
with open('f1') as f1, open('f2') as f2:
for i, r1, r2 in izip_longest(count(), f1, f2, fillvalue=EOF):
if EOF in (r1, r2):
print i, r1, r2
break
你必须使用发电机吗?如果不是,则可以定义一个类,该类可iterable知道如何从文件返回下一行,跟踪相对于总文件大小消耗的字节数,跟踪打开的文件句柄是否被释放,因此,它可以随时报告进度。与其在
下一步时增加计数器,或者在生成器中构建计数器,不如只枚举生成器?@user2357112我不确定我是否理解你的意思。请注意,我在while
循环中的多行上推进(调用next
on)生成器。@obk:您可以将生成器包装在枚举
迭代器中,然后只需next
即可。对于没有内置计数器的gen1
,它看起来像g1=enumerate(gen1(无论什么))
,然后是i,val=next(g1)
。是的,我认为类是一个完美的解决方案。感谢这一点,它极大地清理了我的代码。但是有一件事:我需要手动检查如果len(下一行)==0,而不是eoferor
看到这个。
from itertools import count, izip_longest
EOF = object()
with open('f1') as f1, open('f2') as f2:
for i, r1, r2 in izip_longest(count(), f1, f2, fillvalue=EOF):
if EOF in (r1, r2):
print i, r1, r2
break