Відповіді:
Відповідь на це питання дещо залежить від конкретної реалізації 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 .
Крім того, таким чином весь вміст файлу може бути збережений у змінній, яка може бути бажаною в деяких випадках, замість того, щоб переглядати файли за рядком, як зазначено в попередній відповіді .