Python pathlibを利用した、どこから実行しても読み込めるパスの書き方
三行で
__file__
は実行したファイルのパスを取得するpathlib.Path(__file__)
で、実行したファイルのパスの階層を変更できるpathlib.Path(__file__)
を使ってパスを指定すると、どこから実行しても読み込めるパスが書ける
初めに
仕事で__file__
の使い方を学んだので、備忘録として残しておきます。
dir構成
親ファルダ名はwrite_blog_file
、読み込みたいデータdata/tmp.txt
の中に置いてあり、実行するファイルはsrc/main.py
を想定しています。
. └── write_blog_file ├── data │ └── tmp.txt └── src └── main.py
実行する場所が制限されるパスの書き方
ファイルの中身
tmp.txt
hello world!
main.py
with open('../data/tmp.txt', 'rt') as f: tmp = f.read() print(tmp)
この../data/tmp.txt
が問題となります。
自分がwrite_blog_file/src
にいるとき
ls
をすると
main.py
が返ってくる状況で、
python main.py
を実行すると、
hello world!
という出力結果が得られます。tmp.txt
の中身を読み込めていることがわかります。
自分がwrite_blog_file
にいるとき
ls
をすると
data src
が返ってくる状況で
python src/main.py
を実行すると、
FileNotFoundError: [Errno 2] No such file or directory: '../data/tmp.txt'
と言うエラーが出力されます。
write_blog_file/src
にいたときは../data/tmp.txt
のパスであってましたが、write_blog_file
にいると、相対パスが合わなくなったためですね。
ここで、どこから実行しても、常にdata/tmp.txt
を読み込めるようにしたい気持ちが生まれます。
どこから実行しても読み込めるパスの書き方
pathlib.Path(__file__)
は実行ファイルのパスを取得する
この気持ちはpathlib.Path(__file__)
にて実現できます。
pathlib.Path(__file__)
がどんなものを取得するのか説明するために、新しいファイルcheck_file_output.py
をsrc配下に一つ追加します。
check_file_output.py
from pathlib import Path print(Path(__file__)) print(Path(__file__).parent)
これをwrite_blog_file/src
にて下記のように実行します。
python check_file_output.py
実行結果は以下です。
<my_path>/write_blog_file/src/check_file_output.py <my_path>/write_blog_file/src
※ <my_path>
の部分は、人によって異なるパスが入ります。
これを見ると
Path(__file__)
によって実行したファイルの絶対パスが取得できていることPath(__file__).parent
によって、一つ上の階層を取得できていること
が分かります。
※ Path(__file__)
が絶対パスを返すのはpythonのversionが3.9からの仕様です。3.8以下の場合はPath(__file__)
→Path(__file__).resolve()
と置き換えて下さい。
つまり、Path(__file__)
によって、実行ファイルのパスをベースにして、階層を変更したパスを取得可能であることが分かります。
これを利用すると、どこからファイルを実行しても読み込めるパスの書き方が実現できます。
実行しているファイルの場所と、読み込むファイルの位置関係は常に固定のため、実行しているファイルの場所からの相対パスで読み込むファイルを指定するイメージです。
実際に見てみましょう。
pathlibを利用して、どこからでも実行できるパスを書く
先ほどのmain.py
を、pathlibを利用して書くとこうなります。
main_use_pathlib.py
from pathlib import Path with open(f'{Path(__file__).parents[1]}/data/tmp.txt') as f: tmp = f.read() print(tmp)
parents[1]
は2階層上がることを意味します。
このコードで、先ほどと同様実行する場所を変えてみましょう。
自分がwrite_blog_file/src
にいるとき
下記コマンドを実行します。
python main.py
結果は、
hello world!
となります。
自分がwrite_blog_fileにいるとき
下記コマンドを実行します。
python main.py
結果は、
hello world!
となります。
よって、実行する場所を変えても、ファイルを読み込めるようなパスが書けました。