当脚本因异常而退出时,是否会自动关闭打开的文件(和其他资源)?
我想知道在异常处理期间是否需要关闭我的资源。
**编辑:更具体地说,我在我的脚本中创建了一个简单的日志文件。我想知道是否需要关注在异常情况下显式关闭日志文件。 由于我的脚本有一个复杂的,嵌套的,try / except块,这样做有点复杂,所以如果python,CLIB或操作系统要在脚本崩溃/出错时关闭我的文本文件,我不想浪费太多时间确保文件关闭。
如果Python手册中有一部分涉及此问题,请转介给我,但我找不到它。
答案 0 :(得分:24)
不,他们没有。
如果您希望即使发生异常也要关闭文件,请使用with
语句。
来自docs:
with
语句用于包装块的执行 由上下文管理器定义的方法。这允许共同 尝试...除了...最终要封装的使用模式以便于重复使用。
来自docs:
with
语句允许使用文件等对象,以确保始终及时正确地清理它们。
with open("myfile.txt") as f:
for line in f:
print line,
执行语句后,即使在处理行时遇到问题,文件f
也始终关闭。提供预定义清理操作的其他对象将在其文档中指出这一点。
答案 1 :(得分:19)
一个相当简单的问题。
两个答案。
有人说,“是的。”
另一个说法,“不!”
两者都有重要的赞成票。
谁相信?让我试着澄清一下。
这两个答案对他们都有一些道理,这取决于你的意思 文件被关闭。
首先,考虑从操作系统关闭文件的含义 透视图。
当进程退出时,操作系统clears up all the resources that only that process had open。否则行为拙劣的程序 崩溃但没有释放他们的资源可以消耗所有的系统 资源。
如果Python是打开该文件的唯一进程,那么该文件将会
被关闭同样,操作系统将清除分配的内存
这个过程,任何仍然开放的网络端口,以及其他大多数网络端口
的东西。有一些特殊的功能,如shmat
创建
持续超出过程的对象,但在大多数情况下
操作系统可以处理所有事情。
现在,从Python的角度来看关闭文件呢?如果有任何程序 用任何编程语言编写的退出,大多数资源将被清除 up - 但是Python如何处理标准Python程序中的清理工作?
Python的标准CPython实现 - 与其他Python相反
像Jython这样的实现使用引用计数来完成它的大部分工作
垃圾收集。对象具有引用计数字段。每次
Python中的某些东西获得了对其他对象的引用,引用
引用对象中的计数字段递增。当参考是
丢失,例如,因为变量不再在范围内,引用计数是
递减。当引用计数达到零时,没有Python代码可以达到
对象再次被释放。当它到来时
解除分配,Python calls the __del__()
destructor。
Python的__del__()
文件方法刷新缓冲区并关闭缓冲区
从操作系统的角度来看文件。因为参考
在CPython中计算,如果在函数中打开文件而不返回
文件对象,然后文件上的引用计数下降到零
函数退出,文件自动刷新和关闭。什么时候
程序结束,CPython取消引用所有对象,并且所有对象都有
即使程序因无意义而结束,他们的析构函也会被调用
例外。 (对于你有cycle
of objects with destructors的病态情况,这在技术上是失败的,
至少在Python版本before 3.4中。)
但这只是CPython的实现。 Python定义了语言 在Python language reference中,这就是所有Python 需要实现以实现自己的实现 Python的兼容。
语言参考解释了data model section中的资源管理:
某些对象包含对“外部”资源的引用,例如open 文件或窗口。据了解,这些资源何时被释放 该对象是垃圾收集的,但因为垃圾收集不是 保证会发生,这样的对象也提供了明确的方法 释放外部资源,通常是close()方法。程序是 强烈建议明确关闭此类对象。该 'try ... finally'语句和'with'语句提供方便 如何做到这一点。
也就是说,CPython通常会立即关闭对象,但那可能 在将来的版本中进行更改,而其他Python实现则不然 需要完全关闭对象。
因此,为了便携性和explicit is better than implicit,
强烈建议在可能的所有内容上调用close()
close()
d,如果之间有代码,则在finally
块中执行此操作
对象创建和可能引发异常的close()
。或者使用
完成同样事情的with
句法糖。如果你这样做
即使异常,也会刷新文件上的缓冲区
提高。
但是,即使使用with
语句,相同的基础机制也是如此
工作中。如果程序以不提供Python的方式崩溃
__del__()
方法有机会运行,你仍然可以以腐败结束
磁盘上的文件:
#!/usr/bin/env python3.3
import ctypes
# Cast the memory adress 0x0001 to the C function int f()
prototype = ctypes.CFUNCTYPE(int)
f = prototype(1)
with open('foo.txt', 'w'):
x.write('hi')
# Segfault
print(f())
该程序生成零长度文件。这是一个异常情况,但它
表明即使使用with
语句资源也不会总是如此
必须按照你期望的方式清理。 Python告诉操作
系统打开文件进行写入,在磁盘上创建; Python写hi
进入C库的stdio
缓冲区;然后它在with
之前崩溃
声明结束,并且由于明显的内存损坏,它并不安全
让操作系统尝试读取缓冲区的剩余部分并将其刷新到磁盘。因此,即使有with
语句,程序也无法正常清理。哎呦。尽管如此,close()
和with
几乎总是有效,而且你的程序总是比没有它们更好。
所以答案既不是也不是。 with
语句和close()
在技术上不是
大多数普通的CPython程序都是必需的。但不使用它们会产生结果
看起来不对的非可移植代码。虽然他们非常
有帮助的,他们仍有可能在病理情况下失败。
答案 2 :(得分:3)
是的,他们这样做。
这是一个CLIB(至少在cpython中)和操作系统的东西。当脚本退出时,CLIB将刷新并关闭所有文件对象。即使它没有(例如,python本身崩溃),操作系统就像任何其他进程一样关闭其资源。无论是异常还是正常退出,或者即使它的python或任何其他程序也无关紧要。
这是一个脚本,它在文件内容刷新到磁盘之前写入文件并引发异常。工作正常:
~/tmp/so$ cat xyz.txt
cat: xyz.txt: No such file or directory
~/tmp/so$ cat exits.py
f = open("xyz.txt", "w")
f.write("hello")
print("file is", open("xyz.txt").read())
assert False
~/tmp/so$ python exits.py
('file is', '')
Traceback (most recent call last):
File "exits.py", line 4, in <module>
assert False
AssertionError
~/tmp/so$ cat xyz.txt
hello
答案 3 :(得分:0)
我和这个帖子中的其他人留下了一个问题,“那么最终是真的吗?”
现在,假设文件在过早的程序终止中保持打开状态 - 除了由于文件处理而导致的异常之外还有很多这样的情况 - 避免这种情况的唯一安全方法是读取整个(或部分)将文件放入缓冲区并关闭它。然后根据需要处理缓冲区中的内容。这是特别的。必须在文件上进行全局搜索,更改等的情况。完成更改后,可以立即将整个缓冲区写入相同或其他文件,从而避免将新创建的文件保持打开的风险 - 通过执行大量读数和写入 - 这是最糟糕的情况!