在异常退出期间文件是否关闭?

时间:2013-07-10 17:29:50

标签: python file

当脚本因异常而退出时,是否会自动关闭打开的文件(和其他资源)?

我想知道在异常处理期间是否需要关闭我的资源。

**编辑:更具体地说,我在我的脚本中创建了一个简单的日志文件。我想知道是否需要关注在异常情况下显式关闭日志文件。 由于我的脚本有一个复杂的,嵌套的,try / except块,这样做有点复杂,所以如果python,CLIB或操作系统要在脚本崩溃/出错时关闭我的文本文件,我不想浪费太多时间确保文件关闭。

如果Python手册中有一部分涉及此问题,请转介给我,但我找不到它。

4 个答案:

答案 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)

我和这个帖子中的其他人留下了一个问题,“那么最终是真的吗?”

现在,假设文件在过早的程序终止中保持打开状态 - 除了由于文件处理而导致的异常之外还有很多这样的情况 - 避免这种情况的唯一安全方法是读取整个(或部分)将文件放入缓冲区并关闭它。然后根据需要处理缓冲区中的内容。这是特别的。必须在文件上进行全局搜索,更改等的情况。完成更改后,可以立即将整个缓冲区写入相同或其他文件,从而避免将新创建的文件保持打开的风险 - 通过执行大量读数和写入 - 这是最糟糕的情况!