Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
检查并关闭python生成器_Python - Fatal编程技术网

检查并关闭python生成器

检查并关闭python生成器,python,Python,我有一段代码,它使用生成器读取两个大文件,当其中一个文件达到EOF时停止。我想知道(1)哪台发电机首先达到EOF,(2)每台发电机的进度,即第一台发电机达到EOF时发电机中I的值(见下面的代码),以及(3)另一台发电机中剩余的线路数。我不知道提前多久每个文件,并希望避免预扫描的文件 我知道我可以通过以下方式获得进展: 每次调用next()(这太难看了!)时递增一个计数器,或者 让生成器返回一个计数器(请参见代码中的counter1和counter2) 但在这两种情况下,我都不知道是gen1还是g

我有一段代码,它使用生成器读取两个大文件,当其中一个文件达到EOF时停止。我想知道(1)哪台发电机首先达到EOF,(2)每台发电机的进度,即第一台发电机达到EOF时发电机中
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