Рекомендуемый способ закрытия файлов с помощью модуля pathlib? - PullRequest
6 голосов
/ 24 апреля 2020

Исторически я всегда использовал следующее для чтения файлов в python:

with open("file", "r") as f:
    for line in f:
        # do thing to line

Это все еще рекомендуемый подход? Существуют ли какие-либо недостатки в использовании следующего:

from pathlib import Path

path = Path("file")
for line in path.open():
    # do thing to line

Большинство ссылок, которые я нашел, используют ключевое слово with для открытия файлов, чтобы не было необходимости явно закрывать файл. Это применимо для итераторского подхода здесь?

with open() документы

Ответы [ 3 ]

3 голосов
/ 25 апреля 2020

Имейте в виду, что объект Path предназначен для работы с путями файловой системы. Как и во встроенной библиотеке из Python, существует метод open , но в объекте Path нет закрытия.

.close находится в дескрипторе файла, который возвращается либо встроенным open , либо с помощью метода открытия объекта Path:

>>> from pathlib import Path
>>> p=Path(some_file)
>>> p
PosixPath('/tmp/file')

You Вы можете открыть этот объект Path с помощью встроенной функции open или метода open в объекте Path:

>>> fh=open(p)    # open built-in function
>>> fh
<_io.TextIOWrapper name='/tmp/file' mode='r' encoding='UTF-8'>
>>> fh.close()

>>> fh=p.open()   # Path open method which aliases to os.open
>>> fh
<_io.TextIOWrapper name='/tmp/file' mode='r' encoding='UTF-8'>
>>> fh.close()

Вы можете посмотреть исходный код pathlib на Github в качестве указания на то, как авторы pathlib делают это в своем собственном коде.

То, что я наблюдаю, является одной из трех вещей.

Наиболее распространенным на сегодняшний день является использование with :

from pathlib import Path 

p=Path('/tmp/file')

#create a file
with p.open(mode='w') as fi:
    fi.write(f'Insides of: {str(p)}')

# read it back and test open or closed
with p.open(mode='r') as fi:
    print(f'{fi.read()} closed?:{fi.closed}')

# prints 'Insides of: /tmp/file closed?:False'

Как вы, вероятно, знаете, в конце блока with вызываются методы __exit__. Для файла это означает, что файл закрыт. Это наиболее распространенный подход в исходном коде pathlib.

Во-вторых, в источнике также видно, что объект pathlib поддерживает состояние входа и выхода, а также флаг открытия и закрытия файла. Однако функции os.close явно не вызываются. Вы можете проверить этот статус с помощью аксессора .closed.

fh=p.open()
print(f'{fh.read()} closed?:{fh.closed}')
# prints Insides of: /tmp/file closed?:False    
# fi will only be closed when fi goes out of scope...
# or you could (and should) do fh.close()


with p.open() as fi:
    pass
print(f'closed?:{fi.closed}')   
# fi still in scope but implicitly closed at the end of the with bloc
# prints closed?:True

В-третьих, при cPython файлы закрываются, когда дескриптор файла выходит из области видимости. Это не переносимо или считается «хорошей практикой», на которую можно положиться, но обычно это так. Есть примеры этого в исходном коде pathlib.

1 голос
/ 26 апреля 2020

То, что еще не было упомянуто: если все, что вы хотели сделать, это прочитать или написать какой-то текст (или байты), то вам больше не нужно явно использовать менеджер контекста при использовании pathlib:

>>> import pathlib
>>> path = pathlib.Path("/tmp/example.txt")
>>> path.write_text("hello world")
11
>>> path.read_text()
'hello world'
>>> path.read_bytes()
b'hello world'

При открытии файла для итерации строк все равно следует использовать оператор with по тем же причинам, что и при использовании диспетчера контекста с open, так как в документах показано :

>>> with path.open() as f:
...     for line in f:
...         print(line)
...
hello world
1 голос
/ 25 апреля 2020

Pathlib - это объектно-ориентированный способ манипулирования путями в файловой системе.

Рекомендуемый способ открытия файла с использованием модуля pathlib - использование диспетчера контекста:

p = Path("my_file.txt")

with p.open() as f:
    f.readline()

Это гарантирует закрытие файла после его использования.


В обоих предоставленных вами примерах файлы не закрываются, потому что вы открываете их inplace .

Так как p.open() возвращает объект файла, вы можете проверить это, назначив его и проверив атрибут closed примерно так:

from pathlib import Path

path = Path("file.txt")

# Open the file pointed by this path and return a file object, as
# the built-in open() function does.
f = path.open()
for line in f:
    # do some stuff

print(f.closed)  # Evaluates to False.

...