生成器和文件

gbo*_*ffi 4 python generator generator-expression operator-precedence

我写的时候:

lines = (line.strip() for line in open('a_file'))
Run Code Online (Sandbox Code Playgroud)

文件是立即打开还是仅在我开始使用生成器表达式时才访问文件系统?

MSe*_*ert 5

它立即打开.如果使用不存在的文件名,则可以验证这一点(它将抛出一个异常,表明Python实际上试图立即打开它).

您还可以使用提供更多反馈的函数,以便在迭代生成器之前查看命令是否已执行:

def somefunction(filename):
    print(filename)
    return open(filename)

lines = (line.strip() for line in somefunction('a_file'))  # prints
Run Code Online (Sandbox Code Playgroud)

但是,如果使用生成器函数而不是生成器表达式,则仅在迭代时打开文件:

def somefunction(filename):
    print(filename)
    for line in open(filename):
        yield line.strip()

lines = somefunction('a_file')  # no print!

list(lines)                     # prints because list iterates over the generator function.
Run Code Online (Sandbox Code Playgroud)


NPE*_*NPE 5

open() 在构建生成器时立即调用,无论您何时或是否使用它。

相关规范是PEP-289

早期绑定与晚期绑定

经过多次讨论,决定第一个(最外面的)for 表达式应该立即计算,其余的表达式在生成器执行时计算。

当被要求总结绑定第一个表达式的原因时,Guido 提供了 [5]:

考虑sum(x for x in foo())。现在假设存在一个foo() 引发异常的错误,并且其中的一个错误在sum()开始迭代其参数之前引发了一个异常。您希望看到哪个异常?如果 insum()是one in而不是 in foo(),我会感到惊讶,因为调用 tofoo()是参数 to 的一部分sum(),我希望在调用函数之前处理参数。

OTOH, in sum(bar(x) for x in foo()), wheresum()foo()is bugfree, 但bar()引发异常,我们别无选择,只能将调用延迟bar()sum()开始迭代 - 这是生成器合同的一部分。(next()在第一次调用他们的方法之前,他们什么都不做。)

有关进一步讨论,请参阅该部分的其余部分。