Чтение всего файла в Python

Если вы читаете весь файл с помощью content = open('Path/to/file', 'r').read(), то дескриптор файла остается открытым до выхода script? Есть ли более сжатый метод для чтения целого файла?

Ответ 1

Ответ на этот вопрос зависит от конкретной реализации 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 разных реализаций сборки мусора !

Ответ 2

Вы можете использовать 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()