如果函数lookForSpecificLine
返回True
(即,如果文件"foo.txt"包含targetLine
), Python如何知道关闭文件句柄?文件"foo.txt"会保持打开状态吗?
def lines(filename):
with open(filename, encoding='utf-8') as file:
for line in file:
yield line
def lookForSpecificLine(targetLine):
for line in lines('foo.txt'):
if targetLine == line:
return True
return False
只要生成器对象还活着,文件就会保持打开状态。当生成器被垃圾收集时(通常在lookForSpecificLine
函数的末尾),Python将在其上调用close
,作为PEP 342中描述的协例程协议的一部分。close
方法导致Python在生成器暂停的地方(就在yield
语句之后)抛出一个GeneratorExit
异常。由于您没有捕获该异常(通常不应该),因此它将跳出循环并导致with
语句关闭文件。
请注意,如果lookForSpecificLine
更复杂,并且存在导致异常的一些风险(将在更高级别捕获),则可能无法快速清理。这是因为异常回溯将使函数的堆栈帧保持活动状态,因此生成器不会立即被垃圾收集,文件也不会被关闭。
这样做是因为文件对象也是上下文管理器。基本上,一个类需要定义一个__enter__
和一个__exit__
函数,它们将分别在with
块的开始和结束时被调用。
下面是一个简单的上下文管理器示例,它在with
块的开头打印"on enter",在末尾打印"on exit":
class contextmanager:
def __enter__(self):
print('on enter')
def __exit__(self, type, value, traceback):
print('on exit')
和一个使用它的例子:
>>> with contextmanager():
... print('inside with')
...
on enter
inside with
on exit
现在让我们尝试在with语句中引发一个异常:
>>> with contextmanager():
... raise Exception()
...
on enter
on exit
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
Exception
您可以看到__exit__
函数内部的代码在with
语句的末尾被调用,无论它是正常执行还是引发异常。在文件对象的情况下,它们使用此函数关闭文件句柄并进行清理。
离开with
块后文件关闭。有关with
语句的更多信息,请参见例如PEP343和本指南。