关于在Python中关闭文件
我知道,如果不再在Python中使用,使用close关闭文件是一个好习惯。我试图打开大量打开的文件,但没有关闭它们(在相同的Python过程中),但没有看到任何异常或错误。我试过Mac和Linux。所以,想知道Python是否足够聪明,能够管理文件句柄来自动关闭/重用它们,这样我们就不需要关心文件关闭了 提前感谢,, Lin您确实需要关闭Python中的(输出)文件 其中一个例子就是刷新输出。如果您没有正确地关闭文件,并且您的程序由于某种原因被终止,则左侧打开的文件可能会损坏关于在Python中关闭文件,python,file,Python,File,我知道,如果不再在Python中使用,使用close关闭文件是一个好习惯。我试图打开大量打开的文件,但没有关闭它们(在相同的Python过程中),但没有看到任何异常或错误。我试过Mac和Linux。所以,想知道Python是否足够聪明,能够管理文件句柄来自动关闭/重用它们,这样我们就不需要关心文件关闭了 提前感谢,, Lin您确实需要关闭Python中的(输出)文件 其中一个例子就是刷新输出。如果您没有正确地关闭文件,并且您的程序由于某种原因被终止,则左侧打开的文件可能会损坏 此外,还有这样一个
此外,还有这样一个问题:Python将,一般来说,垃圾收集对象不再使用,也不再被引用。这意味着与垃圾收集器的过滤器匹配的打开文件对象完全有可能被清理,甚至可能被关闭然而;您不应依赖于此,而应使用:
with open(..):
示例(也是最佳实践):
NB:如果您不关闭文件并在系统上留下“打开的文件描述符”,您最终将开始达到系统的资源限制;特别是“ulimit”。您最终将看到与“打开的文件太多”相关的操作系统错误。(假设这里是Linux,但其他操作系统也会有类似的行为)
重要提示:关闭您编写的任何打开的文件也是一种很好的做法,以便正确刷新您编写的数据。这有助于确保数据完整性,并且不会让文件意外地包含由于应用程序崩溃而损坏的数据
值得注意的是,上述重要注意事项是导致文件写入位置出现许多问题的原因;把它读回来;发现它是空的;然后关闭python程序;在文本编辑器中阅读并意识到它不是空的
演示:一个很好的例子,说明如果不确保关闭打开的文件,可能会遇到的资源限制和错误:
$python
Python 2.7.6(默认,2014年3月22日,22:59:56)
[GCC 4.8.2]关于linux2
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
>>>xs=[open(“/dev/null”,“r”)表示xrange(100000)中的uu]
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
IOError:[Errno 24]打开的文件太多:'/dev/null'
处理文件关闭是个好主意。这不是那种会产生错误和异常的东西:它会损坏文件,或者不写你试图写的东西,等等
不过,您可能正在使用的最常见的python解释器CPython会尝试巧妙地处理文件关闭,以防您不这样做。如果您打开一个文件,然后它被垃圾回收,这通常发生在不再有任何对它的引用时,CPython将关闭该文件
例如,如果你有一个函数
def write_something(fname):
f = open(fname, 'w')
f.write("Hi there!\n")
然后Python通常会在函数返回后的某个时间点关闭该文件
对于简单的情况,这并不坏,但是考虑一下:
def do_many_things(fname):
# Some stuff here
f = open(fname, 'w')
f.write("Hi there!\n")
# All sorts of other stuff here
# Calls to some other functions
# more stuff
return something
现在您已经打开了该文件,但它可能需要很长时间才能关闭。在某些操作系统上,这可能意味着其他进程将无法打开它。如果其他内容有错误,您的消息可能实际上不会写入该文件。如果你写了很多东西,其中一些可能是写的,而另一些可能不是;如果你正在编辑一个文件,你可能会引起各种各样的问题。等等
一个有趣的问题是,在OES中,文件可以通过多个进程进行读取,打开一个文件来阅读而不是关闭它有很大的风险。
有两个很好的原因。
def spam():
for i in range(100000):
open('spam.txt') # collected at end of statement
def eggs():
for i in range(100000):
f = open('eggs.txt') # collected next loop, when f is reassigned
def beans():
def toast():
f = open('toast.txt') # collected when toast exits
for i in range(100000):
toast()
但许多其他实现(包括其他三大实现,PyPy、Jython和IronPython)使用更智能的垃圾收集器来动态检测垃圾,而不必跟踪所有引用。这使它们更高效,更擅长线程处理等,但这意味着当对象被收集时它是不确定的。因此,相同的代码将不起作用。或者,更糟糕的是,它会在你的60个测试中起作用,然后在你为投资者做演示时失败 如果您需要PyPy的速度或IronPython的.NET集成,但如果不重写所有代码就无法实现,那将是一个遗憾。或者,如果其他人想使用您的代码,但需要它在Jython中工作,并且必须在其他地方查找
同时,即使在CPython中,解释器也不会在关机时收集所有的垃圾。(它正在变得更好,但即使在3.4版本中也不是完美的。)因此,在某些情况下,您依赖操作系统为您关闭文件。操作系统通常会在这样做时刷新它们,但如果您(例如)在守护进程线程中打开它们,或者您使用
操作系统退出,或者退出时出现故障,则可能不会。(当然,如果有人被电源线绊倒而退出,则绝对不会。)
最后,即使是CPython(我认为是从3.3开始的)也有专门的代码来生成警告,如果您让您的文件被垃圾收集而不是关闭它们。默认情况下,这些警告是关闭的,但人们经常建议打开它们,总有一天会发生这种情况。这是一个错误
def do_many_things(fname):
# Some stuff here
f = open(fname, 'w')
f.write("Hi there!\n")
# All sorts of other stuff here
# Calls to some other functions
# more stuff
return something
def spam():
for i in range(100000):
open('spam.txt') # collected at end of statement
def eggs():
for i in range(100000):
f = open('eggs.txt') # collected next loop, when f is reassigned
def beans():
def toast():
f = open('toast.txt') # collected when toast exits
for i in range(100000):
toast()