Важно ли явно закрывать файлы?

149

В Python, если вы открываете файл без вызова close()или закрываете файл, но не используете try- finallyили withоператор " ", это проблема? Или для практики кодирования достаточно полагаться на сборку мусора Python для закрытия всех файлов? Например, если кто-то делает это:

for line in open("filename"):
    # ... do stuff ...

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

user553702
источник
13
Файл не выходит из области видимости в конце forблока. Его счетчик ссылок станет равным нулю, что приведет к его автоматическому закрытию, но только области, классы и модули определяют области в Python, а не другие составные операторы.
AGF
18
Это не проблема, если только это не проблема. На уровне операционной системы все файлы, открытые сценарием, будут закрыты при выходе из сценария, поэтому вам не нужно беспокоиться о закрытии файлов в сценариях одноразовых инструментов. Однако процессы имеют ограничение на количество открытых файлов, которые они могут поддерживать, поэтому долгоживущие или сложные сценарии могут быть более осторожными. В любом случае, это хорошая привычка закрывать ваши файлы.
Рассел Борогове
3
@agf: Вы правы в том, что файл не выходит из области видимости, но он не связан с различием между forблоками и функциями / классами / модулями. Это гораздо проще: объекты не имеют границ, только имена. Нет имени, которое ссылается на этот объект, поэтому здесь нет ничего, что могло бы оставаться в области видимости или выходить из области видимости.
максимум
@max Мой комментарий исправляет его предположение, что с forциклом связана область видимости , и упоминает, что файл закрывается по совершенно другой причине. Это не касается того, что является областью действия в Python, так как здесь это не актуально.
2012 г.
@max есть неявная ссылка, ограниченная циклом for ... это аргумент семантики
Питер Р.

Ответы:

126

В вашем примере файл не гарантированно будет закрыт до выхода из интерпретатора. В текущих версиях CPython файл будет закрыт в конце цикла for, потому что CPython использует подсчет ссылок в качестве основного механизма сборки мусора, но это деталь реализации, а не особенность языка. Другие реализации Python не гарантированно будут работать таким образом. Например, IronPython, PyPy и Jython не используют подсчет ссылок и поэтому не будут закрывать файл в конце цикла.

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

Для вашего примера используйте:

with open("filename") as f:
     for line in f:
        # ... do stuff ...
Питер Грэм
источник
8
Использование with open() as fавтоматически закрывает файл после того, как это сделано?
Рохан
25
@Rohan да, это небольшая магия, которую withобеспечивает оператор, но, конечно, чтобы эта магия работала, объект должен иметь особые методы, __enter__а __exit__в последнем объект выполняет те closeили иные другие действия по очистке, которые необходимо выполнить на конец withзаявления ...
Копперфильд
1
К вашему сведению: этот ответ объясняет только «когда он будет закрыт», но не объясняет «что если он останется открытым». Для последнего, пожалуйста, прочитайте «Что произойдет, если файл останется открытым?» участие в этом ответе ( askubuntu.com/questions/701491/… )
RayLuo
Кроме того, не закрытие файлов может привести к обрезанию файлов, поскольку содержимое файла не было очищено.
Эрван Легран
Так что, если я не закрою файл, вернусь ли я к своей памяти точно, как только программа остановится? Или я действительно должен выйти из всего переводчика?
Про Q
22

Некоторые Pythons автоматически закрывают файлы, когда на них больше нет ссылок, в то время как другие этого не делают, и это зависит от O / S, чтобы закрыть файлы при выходе из интерпретатора Python.

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

Таким образом, хотя у вас могут не возникнуть проблемы с Python, который вы используете, не рекомендуется оставлять файлы открытыми. Фактически, в cpython 3 теперь вы будете получать предупреждения о том, что система должна была закрыть для вас файлы, если вы этого не сделали.

Мораль: Приведи себя в порядок. :)

Этан Фурман
источник
9
Файлы закрываются, когда на них больше нет ссылок в CPython, но это не языковая функция. Если бы это было так, вы вполне могли бы положиться на это.
Питер Грэм
9

Хотя в данном конкретном случае использование такой конструкции вполне безопасно, существуют некоторые предостережения для обобщения такой практики:

  • run может потенциально исчерпать файловые дескрипторы, хотя вряд ли, представьте себе, что ищите такую ​​ошибку
  • Вы не сможете удалить указанный файл в некоторых системах, например, win32
  • если вы запускаете что-то кроме CPython, вы не знаете, когда файл будет закрыт для вас
  • если вы открываете файл в режиме записи или чтения-записи, вы не знаете, когда данные сбрасываются
Дима Тиснек
источник
3

Файл получает мусор, и, следовательно, закрывается. GC определяет, когда он закроется, а не вы. Очевидно, что это не рекомендуемая практика, потому что вы можете достичь предела количества открытых файлов, если не закрываете файлы, как только заканчиваете их использовать. Что если в этом forцикле вы откроете больше файлов и оставите их в покое?

Нам Нгуен
источник
Но если вы откроете другие файлы в этом цикле for, все равно будет так, что будет открыто более одного файла одновременно, независимо от того, явно вы закрыли какой-либо из них или нет. Вы говорите, что файл не обязательно собирается сборщиком мусора, как только файл выходит из области видимости, поэтому он будет закрыт раньше, если это будет сделано явно? А как насчет того, когда возникает исключение (когда вы используете с / try-finally против того, чтобы не делать этого)?
user553702
1
В CPython подсчет ссылок заставит его собираться после forоператора - вам не придется ждать следующего запуска сборки мусора.
AGF
3

Привет Очень важно закрыть свой файловый дескриптор в ситуации, когда вы собираетесь использовать его содержимое в том же скрипте Python. Я сегодня сама осознаю после столь долгой нерешительной отладки. Причина в том, что контент будет отредактирован / удален / сохранен только после того, как вы закроете дескриптор файла и изменения будут затронуты файлом!

Предположим, у вас есть ситуация, когда вы записываете контент в новый файл, а затем, не закрывая fd, используете этот файл (не fd) в другой команде оболочки, которая читает его содержимое. В этой ситуации вы не сможете получить содержимое для команды оболочки, как ожидалось, и если вы попытаетесь отладить, вы не сможете легко найти ошибку. Вы также можете прочитать больше в моей записи в блоге http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html

Зил Шах
источник
1

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

Python не очищает буфер, то есть записывает данные в файл, пока не будет уверен, что вы закончили запись. Один из способов сделать это - закрыть файл.

Если вы пишете в файл без закрытия, данные не попадут в целевой файл.

Санкет Награле
источник