当脚本因异常退出时,打开的文件(和其他资源)会自动关闭吗?
我想知道在异常处理期间是否需要关闭我的资源.
**编辑:更具体地说,我在我的脚本中创建一个简单的日志文件.我想知道是否需要关注在异常情况下显式关闭日志文件.由于我的脚本有一个复杂的,嵌套的,try/except块,这样做有点复杂,所以如果python,CLIB或操作系统要在脚本崩溃/出错时关闭我的文本文件,我不想浪费太多时间确保文件关闭.
如果Python手册中有一个部分讨论这个问题,请转介我,但我找不到它.
Ash*_*ary 26
不,他们没有.
with如果您希望即使发生异常也要关闭文件,请使用语句.
来自文档:
该
with语句用于使用上下文管理器定义的方法包装块的执行.这允许常见的 尝试...除了...最终使用模式被封装以便于重用.
来自docs:
该with语句允许以一种方式使用文件等对象,以确保始终及时正确地清理它们.
with open("myfile.txt") as f:
for line in f:
print line,
Run Code Online (Sandbox Code Playgroud)
执行语句后f,即使在处理行时遇到问题,也始终关闭文件.提供预定义清理操作的其他对象将在其文档中指出这一点.
and*_*otn 20
一个相当直截了当的问题.
两个答案.
有人说,"是的."
另一个说法是"不!"
两者都有重要的赞成票.
谁相信?让我试着澄清一下.
这两个答案对他们都有一些道理,这取决于你关闭文件的意思.
首先,考虑从操作系统的角度关闭文件的含义.
当进程退出时,操作系统将清除仅该进程已打开的所有资源.否则,崩溃但没有释放其资源的性能不佳的程序可能会占用所有系统资源.
如果Python是打开该文件的唯一进程,则该文件将被关闭.同样,操作系统将清除进程分配的内存,任何仍处于打开状态的网络端口以及大多数其他内容.有一些特殊的功能,比如shmat创建持续超出过程的对象,但在大多数情况下,操作系统会处理所有事情.
现在,从Python的角度来看关闭文件呢?如果任何用任何编程语言编写的程序退出,大多数资源都会被清除 - 但是Python如何在标准Python程序中处理清理?
Python的标准CPython实现 - 与Jython等其他Python实现相反 - 使用引用计数来完成大部分垃圾回收.对象具有引用计数字段.每当Python中的某些东西获得对其他对象的引用时,引用对象中的引用计数字段就会递增.当参考丢失时,例如,因为变量不再在范围内,参考计数减少.当引用计数达到零时,没有Python代码可以再到达对象,因此对象将被释放.当它被解除分配时,Python会调用__del__()析构函数.
Python的__del__()文件方法刷新缓冲区并从操作系统的角度关闭文件.由于引用计数,在CPython中,如果在函数中打开文件而不返回文件对象,则当函数退出时,文件上的引用计数将降为零,并且文件将自动刷新并关闭.当程序结束时,CPython取消引用所有对象,并且所有对象都调用它们的析构函数,即使程序由于无法处理的异常而结束.(对于病毒情况,这在技术上会失败,因为你有一个带有析构函数的对象循环,至少在3.4之前的 Python版本中.)
但这只是CPython的实现.Python语言是在Python语言参考中定义的,这是所有Python实现都需要遵循的,以便称自己与Python兼容.
语言参考在其数据模型部分解释了资源管理:
某些对象包含对"外部"资源的引用,例如打开的文件或窗口.可以理解,当对象被垃圾收集时,这些资源被释放,但由于不能保证垃圾收集发生,这些对象还提供了一种释放外部资源的明确方法,通常是close()方法.强烈建议程序明确关闭此类对象.'try ... finally'语句和'with'语句提供了方便的方法.
也就是说,CPython通常会立即关闭对象,但在将来的版本中可能会发生变化,甚至根本不需要其他Python实现来关闭对象.
因此,为了便于移植并且因为显式优于隐式,强烈建议调用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())
Run Code Online (Sandbox Code Playgroud)
该程序生成零长度文件.这是一个异常情况,但它表明即使使用with语句资源也不一定会按照您期望的方式进行清理.Python告诉操作系统打开一个文件进行写入,然后在磁盘上创建它; Python写入hi
C库的stdio缓冲区; 然后它在with
语句结束之前崩溃,并且由于明显的内存损坏,操作系统尝试读取缓冲区的剩余部分并将它们刷新到磁盘是不安全的.因此即使有with声明,程序也无法正常清理.哎呦.尽管如此,close()并且with几乎总是有效,并且你的程序总是比拥有它们更好.
所以答案既不是也不是.对于大多数普通的CPython程序而言,该with声明并且close()在技术上并不是必需的.但是不使用它们会导致看起来不对的非可移植代码.虽然他们非常
有帮助,但他们仍有可能在病理情况下失败.