Автоматически закрывается ли объект файла, когда его количество ссылок подсчитывается в нуле?
У меня создалось впечатление, что файловые объекты сразу же закрываются, когда их число ссылок достигает 0, поэтому строка:
foo = open('foo').read()
предоставит вам содержимое файла и сразу закроет файл. Однако после прочтения ответа на Is close() необходимо при использовании итератора в объекте Python. У меня создается впечатление, что этого не происходит, и что вызов .close()
для файлового объекта всегда необходимо.
Выполняет ли линия выше то, что я думаю, что она делает, и даже если это так, это питоновская вещь?
Ответы
Ответ 1
Ответ указан в указанной вами ссылке.
Сборщик мусора закрывает файл, когда он уничтожает файл-объект, но:
-
у вас действительно нет контроля над тем, когда это произойдет.
В то время как CPython использует подсчет ссылок для детерминированного выделения ресурсов
(так что вы можете предсказать, когда объект будет уничтожен) другим версиям не нужно.
Например, как Jython, так и IronPython используют сборщик мусора JVM и .NET, который
освобождать (и завершать) объекты только тогда, когда необходимо восстановить память
и может не сделать этого для какого-либо объекта до конца программы.
И даже для CPython GC алгоритм может измениться в будущем как подсчет ссылок
не очень эффективен.
-
если исключение вызывается при закрытии файла при уничтожении объекта файла,
вы не можете ничего с этим поделать, потому что не знаете.
Ответ 2
Если вы хотите быть уверенным, я бы написал код следующим образом:
from __future__ import with_statement
with open('foo') as f:
foo = f.read()
Таким образом, ваш файл закрывается, как ожидалось, даже с исключениями.
Много позже: вот какой-то код с import dis
, чтобы показать, как компилятор рассматривает их по-разному.
>>> def foo(filename):
... with open(filename) as f:
... return f.read()
...
>>> def bar(filename):
... return open(filename).read()
...
>>> from dis import dis
>>>
>>> dis(foo)
2 0 LOAD_GLOBAL 0 (open)
3 LOAD_FAST 0 (filename)
6 CALL_FUNCTION 1
9 DUP_TOP
10 LOAD_ATTR 1 (__exit__)
13 ROT_TWO
14 LOAD_ATTR 2 (__enter__)
17 CALL_FUNCTION 0
20 STORE_FAST 1 (_[1])
23 SETUP_FINALLY 23 (to 49)
26 LOAD_FAST 1 (_[1])
29 DELETE_FAST 1 (_[1])
32 STORE_FAST 2 (f)
3 35 LOAD_FAST 2 (f)
38 LOAD_ATTR 3 (read)
41 CALL_FUNCTION 0
44 RETURN_VALUE
45 POP_BLOCK
46 LOAD_CONST 0 (None)
>> 49 WITH_CLEANUP
50 END_FINALLY
51 LOAD_CONST 0 (None)
54 RETURN_VALUE
>>> dis(bar)
2 0 LOAD_GLOBAL 0 (open)
3 LOAD_FAST 0 (filename)
6 CALL_FUNCTION 1
9 LOAD_ATTR 1 (read)
12 CALL_FUNCTION 0
15 RETURN_VALUE
Ответ 3
Для реализации python cpython: да, он будет закрыт, когда счетчик ссылок будет равен нулю.
Для python как абстрактного языка (например, включая Jython, IronPython и т.д.): нет, он не гарантированно закрыт. В частности, реализация Python может не использовать подсчет ссылок, а использовать другую форму GC.
Литература:
Ответ 4
Нет, Python оптимизирует удаление неиспользуемых объектов, поэтому он никогда не сможет закрыть ваш файл (ОК в конце вашего script на выходе он будет очищать).
@hughdbrown отметили приятное решение.