在Python文件obj上使用迭代器时是否需要close()

这个问题已经在这里有了答案:

  • 明确关闭文件重要吗? 6个答案

是否执行以下操作并且不显式处理文件对象并调用其close()方法是不好的做法吗?

for line in open('hello.txt'):
    print line

注意:这是针对尚没有with语句的Python版本。

我问,因为Python文档似乎建议这样做:

f = open("hello.txt")
try:
    for line in f:
        print line
finally:
    f.close()

这似乎比必要的更为冗长。

Dave M. asked 2020-08-04T23:19:01Z
8个解决方案
66 votes

处理文件时始终必须关闭,最好不要在各处放置打开的文件句柄。 当文件对象被垃圾回收时,它们最终将被关闭,但是您不知道何时会关闭它们,与此同时,您将由于不再需要文件句柄而浪费了系统资源。

如果您使用的是Python 2.5及更高版本,则可以使用with语句自动为您调用with

from __future__ import with_statement # Only needed in Python 2.5
with open("hello.txt") as f:
    for line in f:
        print line

这与您拥有的代码具有相同的效果:

f = open("hello.txt")
try:
    for line in f:
        print line
finally:
    f.close()

with语句是对C ++中常用的“ Resource Acquisition Is Initialization”成语的直接语言支持。 它允许安全使用和清理各种资源,例如,它可以用于始终确保关闭数据库连接或始终释放锁,如下所示。

mylock = threading.Lock()
with mylock:
    pass # do some thread safe stuff
Tendayi Mawushe answered 2020-08-04T23:19:29Z
19 votes

实际上,该文件在被垃圾回收时将被关闭。 有关更多信息,请参见此问题。

仍然建议您使用try/finally块或with语句。 如果在使用文件对象的方法之一时发生异常,则引用将存储在跟踪中(作为全局变量存储),直到您清除它或发生另一个异常为止。

因此,依靠垃圾回收为您关闭文件是很不好的。

另外,如果您已写入文件,则无法保证所做的更改将保存到文件中,除非将其关闭或刷新。

Jason Baker answered 2020-08-04T23:20:02Z
11 votes

奇怪的是,在本主题中有关释放系统资源重要性的所有讨论中,没有人提到确定性关闭文件的一个明显更重要的理由:可以再次打开该文件。

在某些情况下,没关系。 如果文件对象超出范围或被删除,则基础文件将被关闭。 (何时关闭它取决于您使用的Python的特定实现。)通常就足够了-如果您确切知道文件变量何时超出范围,以及是否知道 不必担心文件是否确定关闭。

但是,当存在299717443650951616800语句时,为什么还要进行这种分析呢?

Robert Rossney answered 2020-08-04T23:20:32Z
6 votes

到处都有这种提示,但要使其最清晰,是的,您需要关闭该文件。 在Python 2.5(使用Future)和Python 2.6中,您不再需要冗长的版本:

from __future__ import with_statement
with open("hello.txt") as f:
    for line in f:
        print line
Douglas Mayle answered 2020-08-04T23:20:52Z
5 votes

退出时,Python解释器(或崩溃时的内核)将关闭文件,但是在不需要它们时关闭它们仍然是一个好习惯。 对于1或2或10,文件可能不是问题,但对于更多文件,可能会使整个系统瘫痪。

最重要的是,这表明编写代码的人实际上关心他的工作。

Emil Ivanov answered 2020-08-04T23:21:17Z
3 votes

不,我不认为需要更长的成语,这就是为什么:

我将/usr/lib/python2.6/模式设置为try...finally...close并发现了许多例子

for line in open('hello.txt'):
    print line

到目前为止,有零个实例

f = open("hello.txt")
try:
    for line in f:
        print line
finally:
    f.close()

请参阅以下有关使用try...finally...close惯用语的标准库中文件的列表。

这自然会引出一个问题:如果Python开发人员接受以下简短用法,标准库,我们如何通过使用某些东西来改进任何东西如果我们的代码依赖于标准库,我们自己的代码是否有所不同?

我认为答案是,更长的成语并不能改善任何事情。

我也跑了

#!/usr/bin/env python
try:
    for i,line in enumerate(open('a')):
        print line
        raw_input()
        if i==5:
            break
except Exception:
    pass

raw_input()

并检查try...finally...close是否关闭了文件描述符。看来当您退出for循环时,该文件已为您关闭。

根据这些实验,我相信try...finally...close成语是必要的。

这是grep的结果:

/usr/lib/python2.6/dist-packages/NvidiaDetector/nvidiadetector.py:89:tempList = [ x.strip() for x in open(obsolete).readlines() ]
/usr/lib/python2.6/dist-packages/rpy_io.py:49:for line in open(file).readlines():
/usr/lib/python2.6/dist-packages/setuptools/command/easy_install.py:1376:for line in open(self.filename,'rt'):
/usr/lib/python2.6/dist-packages/GDebi/DscSrcPackage.py:47:for line in open(file):
/usr/lib/python2.6/dist-packages/aptsources/distinfo.py:220:[x.strip() for x in open(value)])
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeCache.py:989:for line in open("/proc/mounts"):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeAufs.py:100:for line in open("/proc/mounts"):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeAufs.py:205:for line in open("/proc/mounts"):
/usr/lib/python2.6/dist-packages/DistUpgrade/distinfo.py:220:[x.strip() for x in open(value)])
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeViewKDE.py:826:for c in open(sys.argv[2]).read():
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeConfigParser.py:45:items = [x.strip() for x in open(p)]
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:684:for line in open(cpuinfo):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:692:for line in open("/proc/mounts"):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:726:for line in open("/etc/fstab"):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:762:for line in open(fstab):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:801:for line in open("/etc/fstab"):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:874:for line in open(XORG):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeQuirks.py:939:for line in open(os.path.join(modaliasesdir,filename)):
/usr/lib/python2.6/dist-packages/DistUpgrade/DistUpgradeController.py:1307:for line in open(template):
/usr/lib/python2.6/dist-packages/DistUpgrade/xorg_fix_proprietary.py:23:for raw in open(xorg_source):
/usr/lib/python2.6/dist-packages/DistUpgrade/xorg_fix_proprietary.py:58:for line in open(xorg):
/usr/lib/python2.6/dist-packages/DistUpgrade/xorg_fix_proprietary.py:82:for line in open(xorg):
/usr/lib/python2.6/dist-packages/jockey/oslib.py:377:for line in open(self.apt_jockey_source):
/usr/lib/python2.6/dist-packages/jockey/oslib.py:393:for line in open(f):
/usr/lib/python2.6/dist-packages/jockey/backend.py:651:for line in open(path):
/usr/lib/python2.6/dist-packages/jockey/detection.py:277:for line in open(alias_file):
/usr/lib/python2.6/dist-packages/jockey/detection.py:597:for l in open(os.path.join(path, 'uevent')):
/usr/lib/python2.6/dist-packages/apt/cdrom.py:83:for line in open(fname):
/usr/lib/python2.6/dist-packages/problem_report.py:1119:for line in open('/proc/mounts'):
/usr/lib/python2.6/dist-packages/apport/packaging_impl.py:128:for line in open(f):
/usr/lib/python2.6/dist-packages/apport/packaging_impl.py:190:for line in open(sumfile):
/usr/lib/python2.6/dist-packages/apport/packaging_impl.py:641:for l in open('/etc/apt/sources.list'):
/usr/lib/python2.6/dist-packages/apport/hookutils.py:190:for line in open('/proc/asound/cards'):
/usr/lib/python2.6/dist-packages/apport/hookutils.py:290:for line in open('/var/log/syslog'):
/usr/lib/python2.6/dist-packages/apport/hookutils.py:493:mods = [l.split()[0] for l in open(module_list)]
/usr/lib/python2.6/dist-packages/softwareproperties/SoftwareProperties.py:597:for line in open(f):
/usr/lib/python2.6/dist-packages/softwareproperties/gtk/SoftwarePropertiesGtk.py:883:for x in open(tmp.name):
/usr/lib/python2.6/dist-packages/lsb_release.py:253:for line in open('/etc/lsb-release'):
/usr/lib/python2.6/dist-packages/numpy/distutils/system_info.py:815:for d in open(ld_so_conf,'r').readlines():
/usr/lib/python2.6/dist-packages/LanguageSelector/LocaleInfo.py:72:for line in open(languagelist_file):
/usr/lib/python2.6/dist-packages/LanguageSelector/LocaleInfo.py:187:for line in open(environment).readlines():
/usr/lib/python2.6/dist-packages/LanguageSelector/LocaleInfo.py:193:for line in open(environment).readlines():
/usr/lib/python2.6/dist-packages/LanguageSelector/LanguageSelector.py:125:for line in open(fname):
/usr/lib/python2.6/dist-packages/LanguageSelector/LanguageSelector.py:140:for line in open(fname):
/usr/lib/python2.6/dist-packages/LanguageSelector/LanguageSelector.py:171:for line in open(fname):
/usr/lib/python2.6/dist-packages/LanguageSelector/LanguageSelector.py:210:for line in open(fname):
/usr/lib/python2.6/dist-packages/LanguageSelector/macros.py:16:for l in open(file):
/usr/lib/python2.6/dist-packages/LanguageSelector/macros.py:37:for l in open(self.LANGCODE_TO_LOCALE):
/usr/lib/python2.6/dist-packages/LanguageSelector/LangCache.py:94:for l in open(self.BLACKLIST):
/usr/lib/python2.6/dist-packages/LanguageSelector/LangCache.py:99:for l in open(self.LANGCODE_TO_LOCALE):
/usr/lib/python2.6/dist-packages/LanguageSelector/LangCache.py:111:for l in open(self.PACKAGE_DEPENDS):
/usr/lib/python2.6/dist-packages/LanguageSelector/ImSwitch.py:78:for l in open(self.blacklist_file):
unutbu answered 2020-08-04T23:22:16Z
3 votes

是的,因为否则可能会泄漏资源。

从Python文档中:

文件处理完毕后,请致电f.close()将其关闭,并释放打开文件占用的所有系统资源。

当程序退出时,这会为您发生,但是Python会保留到此为止不再需要的资源。

Dominic Rodger answered 2020-08-04T23:22:49Z
2 votes

您需要关闭句柄,以便释放内存。 直到一次处理大量文件才真正需要。

Sarfraz answered 2020-08-04T23:23:09Z
translate from https://stackoverflow.com:/questions/1832528/is-close-necessary-when-using-iterator-on-a-python-file-object