Является ли close() необходимым при использовании итератора на файловом объекте Python

Является ли плохой практикой делать следующие и не явно обрабатывать файл-объект и вызывать его метод close()?

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

NB - это для версий Python, которые еще не имеют оператора with.

Я спрашиваю, как выглядит документация на Python: -

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

Что представляется более подробным, чем необходимо.

Ответы

Ответ 1

Закрыть всегда необходимо при работе с файлами, не рекомендуется оставлять открытые дескрипторы файлов повсюду. В конечном итоге они будут закрыты, когда файл-объект будет собран мусором, но вы не знаете, когда это произойдет, и, в то же время, вы будете тратить ресурсы системы, удерживая файлы, которые вам больше не нужны.

Если вы используете Python 2.5 и выше, close() можно вызвать для вас автоматически с помощью инструкции 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 - это прямая поддержка языка Инициализация приобретения ресурсов, обычно используемая в С++. Он позволяет безопасно использовать и очищать всевозможные ресурсы, например, его можно использовать для обеспечения того, чтобы соединения с базой данных были закрыты или блокировки всегда были выпущены, как показано ниже.

mylock = threading.Lock()
with mylock:
    pass # do some thread safe stuff

Ответ 2

В действительности, файл будет закрыт, когда будет собран мусор. См. этот вопрос для получения дополнительной информации о том, как это работает.

Тем не менее, рекомендуется использовать блок try/finally или оператор with. Если существует исключение при использовании одного из методов файлового объекта, ссылка будет храниться в трассировке (которая хранится как глобальная переменная) до тех пор, пока вы не очистите ее или не произойдет другое исключение.

Таким образом, плохо полагаться на сборку мусора, чтобы закрыть файл для вас.

Кроме того, если вы записали файл, вы не можете гарантировать, что изменения будут сохранены в файле до тех пор, пока он не будет закрыт или не будет сброшен.

Ответ 3

Странно, что для всех обсуждений в этой теме о важности освобождения системных ресурсов никто не упомянул о том, что мне кажется явно более важной причиной для деления файла с дефиницией: чтобы его можно было открыть снова.

Есть, конечно, случаи, когда это не имеет значения. Если файл-объект выходит из области видимости или удаляется, основной файл будет закрыт. (Когда он закрывается, зависит от конкретной реализации Python, который вы используете.) Обычно это будет достаточно хорошо - если вы точно знаете, когда переменная файла выйдет за пределы области видимости, и если вы знаете, что не знаете, t, если файл закрывается детерминированным образом.

Но почему вы должны беспокоиться о таком анализе, когда существует оператор with?

Ответ 4

Это как бы намекнулось повсюду, но чтобы сделать это наиболее ясно, да, вам нужно закрыть этот файл. В Python 2.5 (используя будущее), а в Python 2.6 вам больше не нужна текстовая версия:

from __future__ import with_statement
with open("hello.txt") as f:
    for line in f:
        print line

Ответ 5

После выхода интерпретатор Python (или ядро ​​в случае сбоя) закроет файл, но по-прежнему рекомендуется закрыть их, когда они вам не нужны. Для 1 или 2 или 10 файлов это может быть не проблема, но для большего, это может привести к снижению всей системы.

Самое главное, это знак того, что человек, который на самом деле написал код , заботится о своей работе.

Ответ 6

Нет, я не верю, что более длинная идиома необходима, и вот почему:

I grepped/usr/lib/python2.6/для шаблона 'for\s+.*\s+in\s+open\(' и нашел много примеров

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

и до сих пор нулевые экземпляры

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

Ниже приведен список файлов в стандартной библиотеке, в которых используется for ... in open idiom.

Это, естественно, приводит к вопросу: если разработчики 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()

и отметьте /proc/PID/fd, когда дескриптор файла был закрыт. Похоже, что когда вы выходите из цикла 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):

Ответ 7

Вам нужно закрыть ручки, чтобы освободить память. На самом деле не требуется, чтобы иметь дело с большим количеством файлов за раз.

Ответ 8

Да, поскольку в противном случае вы могли бы утечка ресурсов.

Когда вы делаете файл, звоните f.close(), чтобы закрыть его и освободить системные ресурсы, занятые открытым файл.

Из Документы Python.

Это произойдет для вас, когда программа выйдет, но в остальном Python, поддерживающий ресурсы, больше не нуждается в этом.