Объекты файлов Python, закрытие и деструкторы

описание tempfile.NamedTemporaryFile() говорит:

если удалить имеет значение true (по умолчанию), то файл удаляется, как только он закрывающийся.

в некоторых случаях, это означает, что файл не удаляется после Интерпретатор Python заканчивается. Например, при выполнении следующего теста py.test временный файл остается:

from __future__ import division, print_function, absolute_import
import tempfile
import unittest2 as unittest
class cache_tests(unittest.TestCase):
    def setUp(self):
        self.dbfile = tempfile.NamedTemporaryFile()
    def test_get(self):
        self.assertEqual('foo', 'foo')

в некотором роде это имеет смысл, потому что эта программа никогда явно закрыть файл объект. Единственный способ закрыть объект предположительно в __del__ деструктор, но вот язык ссылки гласит, что"это не гарантируется, что __del__() методы вызываются объекты, которые все еще существуют при выходе интерпретатора." так пока все согласуется с документацией.

тем не менее, я смущен последствиями этого. Если это не так гарантированный что объекты файла закрыты на выходе интерпретатора, могут он возможно, некоторые данные, которые были успешно записаны в (буферизованный) объект file теряется, даже если программа завершает работу изящно, поскольку он все еще находился в буфере объекта file, а объект file никогда не закрывался?

почему-то это кажется очень маловероятным и ООН-подходящие для Python мне, и открытый() документация также не содержит таких предупреждений. Так Что Я ... (предварительно) сделать вывод, что файловые объекты, в конце концов, гарантированно закрывать.

но как это волшебство случается, и почему не может NamedTemporaryFile() использовать та же магия, чтобы убедиться, что файл удален?

Edit: обратите внимание, что я не говорю о файле дескрипторов здесь (которые буферизуются ОС и закрываются ОС при выходе из программы), но о файловых объектах Python, которые могут реализовать свою собственную буферизацию.

3 ответов


В Windows NamedTemporaryFile использует расширение для Windows (os.O_TEMPORARY), чтобы убедиться, что файл удаляется при его закрытии. Это, вероятно, также работает, если процесс каким-либо образом убит. Однако в POSIX нет очевидного эквивалента, скорее всего, потому, что в POSIX вы можете просто удалить файлы, которые все еще используются; он удаляет только имя, а содержимое файла удаляется только после его закрытия (в любом случае). Но действительно предполагая, что мы хотим, чтобы имя файла сохранялось пока файл не закрыт, как с NamedTemporaryFile, тогда нам нужна "магия".

мы не можем использовать ту же магию для промывки буферизованных файлов. Происходит то, что библиотека C обрабатывает его (в Python 2): файлы являются файловыми объектами в C, и C гарантирует, что они будут сброшены при обычном выходе из программы (но не если процесс убит). В случае Python 3 Существует пользовательский код C для достижения того же эффекта. Но это специфично для этого случая использования, а не напрямую многократно используемый.

вот почему NamedTemporaryFile использует пользовательский __del__. И действительно, __del__ не гарантируется вызов при выходе интерпретатора. (Мы можем доказать это с помощью глобального цикла ссылок, который также ссылается на экземпляр NamedTemporaryFile; или запуск PyPy вместо CPython.)

в качестве примечания, NamedTemporaryFile может быть реализован немного более надежно, например, путем регистрации себя с atexit чтобы убедиться, что имя файла удаляется затем. Но вы можете назовите это и сами: если ваш процесс не использует неограниченное количество NamedTemporaryFiles, это просто atexit.register(my_named_temporary_file.close).


в любой версии *nix все файловые дескрипторы закрываются после завершения процесса, и об этом заботится операционная система. Windows, вероятно, точно так же в этом отношении. Не копаясь в исходном коде, я не могу сказать со 100% авторитетом, что на самом деле происходит, но, вероятно, что происходит:

  • если delete is False, (или аналогичная ему функция в других операционных системах). Это означает, что файл будет автоматически удалено когда процесс закончится, и больше нет открытых файловых дескрипторов. Пока процесс выполняется, файл по-прежнему будет оставаться вокруг.

  • если delete is True, вероятно, функция C есть. Это приведет к принудительному удалению файла до завершения процесса.


буферизация файлов обрабатывается операционной системой. Если вы не закрываете файл после его открытия, это происходит потому, что вы предполагаете, что операционная система очистит буфер и закроет файл после существования владельца. Это не магия Python, это ваша ОС делает это. The __del__() метод связан с Python и требует явных вызовов.