web-dev-qa-db-ja.com

pathlibモジュールを使用してファイルを閉じる推奨方法は?

歴史的に私は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() docs

6
Ben Carley

Pathオブジェクトはファイルシステムパスを操作するためのものであることに注意してください。 Pythonの built-in library と同様に、- open メソッドがありますが、Pathオブジェクトにはcloseはありません。

.closeは、組み込み open またはPathオブジェクトのopenメソッドを使用して返されるファイルハンドルにあります。

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

そのPathオブジェクトは、組み込みのopen関数またはPathオブジェクトのopenメソッドのいずれかで開くことができます。

>>> 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()

Githubのpathlib のソースコードを見ると、pathlibの作成者が独自のコードでどのように行うかを確認できます。

私が観察しているのは、3つのことの1つです。

最も一般的なのは、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ソースコードで最も一般的な方法です。

2番目に、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

3番目に、cPythonでは、ファイルハンドルが範囲外になると、ファイルが閉じます。これは移植性がなく、信頼できる「良い習慣」とは考えられていませんが、一般的にはそうです。 pathlibソースコードにこのインスタンスがあります。

3
dawg

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.

_
1
Dinko Pehar

まだ言及されていないもの:やりたいことがいくつかのテキスト(またはバイト)の読み取りまたは書き込みである場合、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'

ファイルを開いて行を繰り返す場合は、コンテキストマネージャをopenと一緒に使用するのと同じ理由で ドキュメントの表示 と同じ理由で、引き続きwithステートメントを使用する必要があります。

>>> with path.open() as f:
...     for line in f:
...         print(line)
...
hello world
1
wim