【问题标题】:StopIteration after defining xrange定义 xrange 后的 StopIteration
【发布时间】:2016-03-29 19:08:16
【问题描述】:

我编写了以下代码来定义文本文件中的 4 行块,如果块的第 2 行仅由一种类型的字符组成,则输出该块。假设(并且之前已验证)第二行总是由 36 个字符组成的字符串。

# filter out homogeneous reads

import sys
import collections
from collections import Counter

filename1 = sys.argv[1] # file to process

with open(filename1,'r') as input_file:
    for line1 in input_file:
        line2, line3, line4 = [next(input_file) for line in xrange(3)]
        c = Counter(line2).values() # count characters in line2
        c.sort(reverse=True) # sort values in descending order
        if c[0] < 36:
            print line1 + line2 + line3 + line4.rstrip()

但是,我收到如下 StopIteration 错误。如果有人能告诉我原因,我将不胜感激。

$ python code.py test.file > testout.file
Traceback (most recent call last):
  File "code.py", line 11, in <module>
    line2, line3, line4 = [next(input_file) for line in xrange(3)]
StopIteration

任何帮助都将不胜感激,尤其是能够解释我的特定代码有什么问题以及如何修复它的帮助。这是一个输入示例:

@1:1:1323:1032:Y
AGCAGCATTGTACAGGGCTATCATGGAATTCTCGGG
+1:1:1323:1032:Y
HHHBHHBHBHGBGGGH8HHHGGGGFHBHHHHBHHHH
@1:1:1610:1033:Y
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+1:1:1610:1033:Y
HHEHHHHHHHHHHHBGGD>GGD@G8GGGGDHBHH4C
@1:1:1679:1032:Y
CGGTGGATCACTCGGCTCGTGCGTCGATGAAGAACG

【问题讨论】:

  • for 循环和列表解析都在遍历文件,也许您应该将其合理化为单个循环?
  • 你的 for 循环中已经有一个隐含的next(input_file);你是否考虑过一个?
  • 你文件中的行数能被4整除吗?
  • 该死...是的,我使用head 命令默认设置生成了该测试输入...但是,@poke 下面的答案非常有启发性,并指出了我的代码中的其他缺点,这很不错:)

标签: python python-2.x stopiteration


【解决方案1】:

您的示例输入已经显示了问题:那里有 10 行,不能被 4 整除。因此,当您阅读最后一个块时,您会得到 line1line2 但对于 next() 调用line3,输入用尽了,什么也得不到。

您的完整输入文件中很可能也有同样的问题:行数根本不能被 4 整除。

有几种方法可以克服这个问题。最好的方法可能是修复您的输入,因为您似乎一直期待四行,如果这不是输入文件给出的内容,似乎存在内容问题。

另一个非常简单的解决方法是使用 next() 指定默认值:

line2, line3, line4 = [next(input_file, '') for line in xrange(3)]

现在,当 next() 失败时,将返回默认值 ''。所以即使文件用尽了,你仍然可以取回一些内容。

然而,一个可能更好的解决方案是修复您迭代文件的方式。您有两个位置可以访问同一个文件迭代器,一次在外部 for 循环中,三次在列表推导中。它可能看起来很简单,因此您不会遇到其他问题,但是您应该真正尝试更改它,以便您只有一个位置可以遍历迭代器;或者只使用 next() 调用,但将其与 for 循环混合似乎是个坏主意。

例如,您可以使用 grouper itertools recipe 以四个一组的方式干净地迭代文件:

with open(filename1, 'r') as input_file:
    for line1, line2, line3, line4 in grouper(input_file, 4, fillvalue=''):
        # do things with the lines

【讨论】:

  • "或者只使用 next() 调用" itertools。
  • 我的意思是 Mike Müller 在第二个例子中展示的内容;我的观点是,你不应该同时拥有 for 循环和单独的 next() 调用迭代文件。相反,您应该只有一种方法来迭代文件,例如要么使用 for 循环,要么使用 next() 调用。这样,您始终可以准确地知道文件被迭代的时间和原因。
  • 我确实试过了,但即使查看了您提供的链接,我也无法使用grouper() 功能。也许我太菜鸟了,但是 Mike Müller 的解决方案对我来说是最简单和最容易的,所以经过仔细考虑,我会选择那个(Abu 的类似,但不需要打印错误消息输出)。再次感谢您的帮助!
  • 当然,最终使用哪种解决方案完全取决于您:) 至于 grouper 函数,您使用它的方式是将函数定义复制到您自己的代码中;此外,您需要在脚本中添加以下导入:from itertools import izip_longest
  • (顺便说一句。接受答案不一定需要与您最终使用的解决方案相匹配。general opinion 是您应该接受对您最有帮助的那个。)
【解决方案2】:

如果您的文件中的行数不能除以4 而没有余数,您将得到此信息。然后,您将尝试读取不存在的行。您需要计算空行数。

如果行数不足以处理,一个解决方案是停止处理文件:

try:
    line2, line3, line4 = [next(input_file) for line in xrange(3)]
except StopIteration:
    break

这感觉有点干净:

while True:
    try:
        line1, line2, line3, line4 = [next(input_file) for line in xrange(4)]
except StopIteration:
    break

因为你只在一个地方而不是两个地方推进迭代器。

【讨论】:

    【解决方案3】:

    您有10 行,因此它可以迭代2times,然后出现2 行短缺。这是 Python 无法读取足够行并抛出 StopIteration 的地方。

    签出这段代码,我稍微更新了一下:

    import sys
    import collections
    from collections import Counter
    
    filename1 = sys.argv[1] # file to process
    
    with open(filename1,'r') as input_file:
        while True:
            try:
                line1, line2, line3, line4 = [next(input_file) for line in xrange(4)]
            except StopIteration:
                print "Not enough lines to read!"
                break
    
            c = Counter(line2).values() # count characters in line2
            c.sort(reverse=True) # sort values in descending order
            if c[0] < 36:
                print line1 + line2 + line3 + line4.rstrip()
            else:
                print "Skipping 4 lines since less than 36 characters"
    

    【讨论】:

    • @poke 我之所以喜欢这个回复,是因为它教会了我一些关于如何使用异常的知识。 @Abu Ashraf Masnun 不应该是 xrange(3)
    • 我建议您标记@poke 的答案,因为他比我更详细。我的答案没有被选中也没关系。
    • 不,如果您注意到,我正在使用 while 循环并将 line1 与其他循环一起移动。所以我必须再次迭代。这就是为什么它是xrange(4)
    • 这个异常似乎在计算成功的情况下也将错误信息添加到文件末尾(最后一行行逻辑上后跟一个StopIteration)
    • 您删除打印消息。
    猜你喜欢
    • 1970-01-01
    • 2018-04-01
    • 2019-10-04
    • 2015-09-15
    • 1970-01-01
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多