Объекты файлов 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
isFalse
, (или аналогичная ему функция в других операционных системах). Это означает, что файл будет автоматически удалено когда процесс закончится, и больше нет открытых файловых дескрипторов. Пока процесс выполняется, файл по-прежнему будет оставаться вокруг.если
delete
isTrue
, вероятно, функция C есть. Это приведет к принудительному удалению файла до завершения процесса.
буферизация файлов обрабатывается операционной системой. Если вы не закрываете файл после его открытия, это происходит потому, что вы предполагаете, что операционная система очистит буфер и закроет файл после существования владельца. Это не магия Python, это ваша ОС делает это. The __del__()
метод связан с Python и требует явных вызовов.