当我写:
lines = (line.strip() for line in open('a_file'))
当我开始使用生成器表达式时,文件是立即打开还是仅访问文件系统?
答案 0 :(得分:5)
立即打开。如果你使用一个不存在的文件名,你可以验证这个(它会抛出一个异常,表明Python实际上试图立即打开它。)
您还可以使用提供更多反馈的函数,以便在迭代生成器之前查看命令的执行:
def somefunction(filename):
print(filename)
return open(filename)
lines = (line.strip() for line in somefunction('a_file')) # prints
但是,如果使用生成器函数而不是生成器表达式,则仅在迭代时打开文件:
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.
答案 1 :(得分:4)
open()
。
相关规范为PEP-289:
早期结合与晚期结合
经过多次讨论,确实如此 决定应该评估第一个(最外面的)for-expression 立即和剩余的表达式进行评估时 生成器被执行。
要求总结绑定第一个表达式的原因, Guido提供了[5]:
考虑
sum(x for x in foo())
。现在假设foo()
中有一个错误 引发异常,以及sum()
中引发异常的错误 在它开始迭代它的参数之前。会有哪个例外 你期待看到吗?如果sum()
中的那个人被提出,我会感到惊讶 而是foo()
中的那个,因为对foo()
的调用是其中的一部分sum()
的参数,我希望参数在...之前得到处理 函数被调用。OTOH,
sum(bar(x) for x in foo())
,sum()
和foo()
bugfree,但是bar()
引发了异常,我们别无选择,只能拖延 调用bar()
直到sum()
开始迭代 - 这是...的一部分 发电机合同。 (他们在next()
方法之前什么都不做 首先叫。)
有关进一步讨论,请参阅该部分的其余部分。
答案 2 :(得分:1)
立即打开。
示例:
def func():
print('x')
return [1, 2, 3]
g = (x for x in func())
输出:
x
该函数需要返回一个可迭代对象。
open()
返回一个可迭代的打开文件对象。
因此,在定义生成器表达式时将打开该文件。