CodeQL 文档

生成器中未受保护的 next

ID: py/unguarded-next-in-generator
Kind: problem
Security severity: 
Severity: warning
Precision: very-high
Tags:
   - maintainability
   - portability
Query suites:
   - python-security-and-quality.qls

单击以查看 CodeQL 代码库中的查询

函数 next() 如果底层迭代器耗尽,将引发 StopIteration 异常。通常情况下,这没有问题,但在生成器中可能会导致问题。由于 StopIteration 是一个异常,因此它将从生成器中传播出去,导致生成器终止。这不太可能是预期行为,并且可能会掩盖错误。

此问题被认为足够严重,以至于已接受 PEP 479 来修改对生成器中 StopIteration 的处理。因此,不能正确处理 StopIteration 的代码在 Python 的未来版本中可能会失败。

建议

next() 的每次调用都应该用 try-except 包裹,以显式地处理 StopIteration 异常。

示例

在以下示例中,迭代过程中的空文件将静默地截断输出,因为 StopIteration 异常将传播到顶层。


test_files = [
    ["header1", "text10", "text11", "text12"],
    ["header2", "text20", "text21", "text22"],
    [],
    ["header4", "text40", "text41", "text42"],
]

def separate_headers(files):
    for file in files:
        lines = iter(file)
        header = next(lines) # Will raise StopIteration if lines is exhausted
        body = [ l for l in lines ]
        yield header, body

def process_files(files):
    for header, body in separate_headers(files):
        print(format_page(header, body))

在以下示例中,显式地处理了 StopIteration 异常,从而允许处理所有文件。


def separate_headers(files):
    for file in files:
        lines = iter(file)
        try:
            header = next(lines) # Will raise StopIteration if lines is exhausted
        except StopIteration:
            #Empty file -- Just ignore
            continue
        body = [ l for l in lines ]
        yield header, body

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私