Ответы:
Ответ на этот вопрос зависит от конкретной реализации Python.
Чтобы понять, о чем это все, обратите особое внимание на реальный file
объект. В вашем коде этот объект упоминается только один раз в выражении и становится недоступным сразу после read()
возврата вызова.
Это означает, что файловый объект является мусором. Единственный оставшийся вопрос - «Когда сборщик мусора соберет объект файла?».
в CPython, который использует счетчик ссылок, этот вид мусора замечается немедленно, и поэтому он будет немедленно собран. Обычно это не так для других реализаций Python.
Лучшее решение, чтобы убедиться, что файл закрыт, это шаблон:
with open('Path/to/file', 'r') as content_file:
content = content_file.read()
который всегда будет закрывать файл сразу после окончания блока; даже если происходит исключение.
Редактировать: чтобы поставить более тонкую точку на нем:
Кроме того file.__exit__()
, что «автоматически» вызывается в with
настройке диспетчера контекста, единственный другой способ, который file.close()
вызывается автоматически (то есть, кроме явного его вызова самостоятельно), - через file.__del__()
. Это приводит нас к вопросу о том, когда звонят __del__()
?
Правильно написанная программа не может предполагать, что финализаторы когда-либо будут работать в любой момент до завершения программы.
- https://devblogs.microsoft.com/oldnewthing/20100809-00/?p=13203
В частности:
Объекты никогда не уничтожаются явно; однако, когда они становятся недоступными, они могут быть собраны мусором. Реализация может откладывать сборку мусора или вообще ее опускать - это вопрос качества реализации, как осуществляется сборка мусора, если не собраны объекты, которые все еще доступны.
[...]
CPython в настоящее время использует схему подсчета ссылок с (опционально) отложенным обнаружением циклически связанного мусора, который собирает большинство объектов, как только они становятся недоступными, но не гарантирует сбор мусора, содержащего циклические ссылки.
- https://docs.python.org/3.5/reference/datamodel.html#objects-values-and-types
(Акцент мой)
но, как предполагается, другие реализации могут иметь другое поведение. Например, в PyPy есть 6 разных реализаций сборки мусора !
__exit__()
в таких случаях звучит как недостаток дизайна.
try
/ из-за finally
того , что он неуклюжий и чрезвычайно распространенный бесполезный из обработчиков очистки, который with
решается. Разница между «явным закрытием» и «управлением с with
» заключается в том, что обработчик выхода вызывается, даже если выдается исключение. Вы могли бы поместить close()
в finally
предложение, но это не сильно отличается от использования with
вместо этого, немного более грязный (3 дополнительные строки вместо 1), и немного сложнее сделать правильно.
with foo() as f: [...]
в основном то же самое f = foo()
, что f.__enter__()
, [...] и f.__exit__()
с обработанными исключениями , так что __exit__
всегда вызывается. Таким образом, файл всегда закрывается.
Вы можете использовать pathlib .
Для Python 3.5 и выше:
from pathlib import Path
contents = Path(file_path).read_text()
Для более старых версий Python используйте pathlib2 :
$ pip install pathlib2
Затем:
from pathlib2 import Path
contents = Path(file_path).read_text()
Это фактическая read_text
реализация :
def read_text(self, encoding=None, errors=None):
"""
Open the file in text mode, read it, and close the file.
"""
with self.open(mode='r', encoding=encoding, errors=errors) as f:
return f.read()
Ну, если вам нужно читать файл построчно для работы с каждой строкой, вы можете использовать
with open('Path/to/file', 'r') as f:
s = f.readline()
while s:
# do whatever you want to
s = f.readline()
Или еще лучше
with open('Path/to/file') as f:
for line in f:
# do whatever you want to
Вместо извлечения содержимого файла в виде одной строки может быть удобно сохранить содержимое в виде списка всех строк, которые содержит файл :
with open('Path/to/file', 'r') as content_file:
content_list = content_file.read().strip().split("\n")
Как видно, нужно добавить сцепленные методы .strip().split("\n")
к основному ответу в этой теме .
Здесь .strip()
просто удаляются пробелы и символы новой строки в конце всей строки файла, и .split("\n")
создается фактический список путем разделения всей строки файла на каждый символ новой строки \ n .
Более того, таким образом все содержимое файла может храниться в переменной, которая может быть желательна в некоторых случаях, вместо того, чтобы циклически перемещаться по файлу, как указывалось в предыдущем ответе .