Pythonで実行中のファイルの場所(パス)を取得する__file__
Pythonで実行中のスクリプトファイル.py
の場所(パス)を取得するには__file__
を使う。実行中のファイルの場所を基準にほかのファイルを読み込んだりする場合に便利。
Python3.8までは、__file__
で得られるのは実行時にpython
コマンド(環境によってはpython3
コマンド)で指定したパス。相対パスで指定すると相対パス、絶対パスで指定すると絶対パスが返される。
Python3.9以降は、実行時に指定したパスによらず絶対パスが返される。
本記事のサンプルコードは以下のディレクトリで作業するものとする。pwd
はシステムのコマンド。Windowsではpwd
ではなくdir
コマンドでカレントディレクトリを確認できる。
pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook
Pythonコード内でのカレントディレクトリの取得、変更については以下の記事を参照。
なお、Jupyter Notebook(.ipynb
)では__file__
は使えないので注意。Jupyter Notebookを起動させたディレクトリによらず、.ipynb
があるディレクトリがカレントディレクトリとして実行される。コードの中でos.chdir()
を使ってカレントディレクトリを変更することは可能。
os.getcwd()と__file__
カレントディレクトリの下の階層(data/src
)に以下の内容のPythonのスクリプトファイル(file_path.py
)を作成。
import os
print('getcwd: ', os.getcwd())
print('__file__: ', __file__)
python
コマンド(環境によってはpython3
コマンド)でスクリプトファイルのパスを指定して実行する。
python3 data/src/file_path.py
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__: data/src/file_path.py
os.getcwd()
でカレントディレクトリの絶対パスが、__file__
でpython3
コマンドで指定したパスが取得できている。
Python3.8までは__file__
にはpython
(またはpython3
)コマンドで指定したパスがそのまま格納される。上の例では相対パスで指定したので相対パスが返されているが、絶対パスで指定した場合は絶対パスが返される。
pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook
python3 /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
Python3.9以降は__file__
はpython
(またはpython3
)コマンドで指定したパスによらず絶対パスを返すようになった。
以降の例では、Python3.7において同じスクリプトファイル(file_path.py
)にコードを追記して上記のディレクトリから相対パスで指定して実行するものとする。
なお、__file__
が絶対パスの場合(Python3.9以降、またはPython3.8以前で絶対パスで指定した場合)も以降の説明と同じコードで実行中のファイルの場所を基準にほかのファイルを読み込んだりする処理が可能。Python3.7において絶対パスで指定して実行した結果は最後にまとめて示す。
実行中のファイルのファイル名、ディレクトリ名を取得
実行中のファイルのファイル名、ディレクトリ名を取得するには、標準ライブラリのos.path
モジュールのos.path.basename()
, os.path.dirname()
関数を使う。
import os
print('basename: ', os.path.basename(__file__))
print('dirname: ', os.path.dirname(__file__))
実行結果。
# basename: file_path.py
# dirname: data/src
実行中のファイルの絶対パスを取得
__file__
で相対パスを取得した場合はos.path.abspath()
で絶対パスに変換できる。ディレクトリも絶対パスで取得可能。
import os
print('abspath: ', os.path.abspath(__file__))
print('abs dirname: ', os.path.dirname(os.path.abspath(__file__)))
実行結果。
# abspath: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
os.path.abspath()
に絶対パスを指定した場合はそれがそのまま返されるので、__file__
が絶対パスの場合にos.path.abspath(__file__)
としてもエラーにはならない。
実行中のファイルの場所を基準にほかのファイルを読み込み
実行中のファイルの場所(パス)を基準にほかのファイルを読み込むには、実行ファイルのディレクトリと読み込みたいファイルの実行ファイルからの相対パスをos.path.join()
で連結する。
実行中のファイルと同じディレクトリのファイルを読み込む場合はファイル名のみを連結すればよい。
import os
print('[set target path 1]')
target_path_1 = os.path.join(os.path.dirname(__file__), 'target_1.txt')
print('target_path_1: ', target_path_1)
print('read target file:')
with open(target_path_1) as f:
print(f.read())
実行結果。
# [set target path 1]
# target_path_1: data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
上の階層(上位レベル)は../
で表す。そのままでも問題はないが、os.path.normpath()
を使うとパスを正規化して余分な../
などを除去できる。
print('[set target path 2]')
target_path_2 = os.path.join(os.path.dirname(__file__), '../dst/target_2.txt')
print('target_path_2: ', target_path_2)
print('normalize : ', os.path.normpath(target_path_2))
print('read target file:')
with open(target_path_2) as f:
print(f.read())
実行結果。
# [set target path 2]
# target_path_2: data/src/../dst/target_2.txt
# normalize : data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
ファイルの読み込みについては以下の記事を参照。
カレントディレクトリを実行中のファイルのディレクトリに移動
スクリプト内でカレントディレクトリを実行中のファイルのディレクトリに移動するにはos.chdir()
を使う。
os.getcwd()
で移動していることが確認できる。
import os
print('[change directory]')
os.chdir(os.path.dirname(os.path.abspath(__file__)))
print('getcwd: ', os.getcwd())
実行結果。
# [change directory]
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
カレントディレクトリを移動してしまえば、ファイルを読み込むときに実行中のファイルのディレクトリと連結する必要はない。実行中のファイルのディレクトリからの相対パスをそのまま指定すればよい。
print('[set target path 1 (after chdir)]')
target_path_1 = 'target_1.txt'
print('target_path_1: ', target_path_1)
print('read target file:')
with open(target_path_1) as f:
print(f.read())
print()
print('[set target path 2 (after chdir)]')
target_path_2 = '../dst/target_2.txt'
print('target_path_2: ', target_path_2)
print('read target file:')
with open(target_path_2) as f:
print(f.read())
実行結果。
# [set target path 1 (after chdir)]
# target_path_1: target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2 (after chdir)]
# target_path_2: ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
実行時のカレントディレクトリに依存せず同じ処理が可能
これまでに示したように、
- 実行中のファイルのディレクトリと、読み込みたいファイルの実行中のファイルからの相対パスを、
os.path.join()
で連結 - カレントディレクトリを実行中のファイルのディレクトリに移動
のいずれかの方法で、実行時のカレントディレクトリに依存せず、スクリプトファイルの場所を基準にファイルを読み込むことが可能。
カレントディレクトリを移動するほうが楽だが、当然ながら、そのあとでさらにファイルの読み書きなどを行う場合は、カレントディレクトリが移動されていることを考慮する必要があるので要注意。
これまでの例の結果をまとめて示す。
pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook
python3 data/src/file_path.py
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__: data/src/file_path.py
# basename: file_path.py
# dirname: data/src
# abspath: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
#
# [set target path 1]
# target_path_1: data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2]
# target_path_2: data/src/../dst/target_2.txt
# normalize : data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
#
# [change directory]
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
#
# [set target path 1 (after chdir)]
# target_path_1: target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2 (after chdir)]
# target_path_2: ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
絶対パスで指定した結果は以下の通り。
pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook
python3 /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook
# __file__: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# basename: file_path.py
# dirname: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# abspath: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
#
# [set target path 1]
# target_path_1: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2]
# target_path_2: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/../dst/target_2.txt
# normalize : /Users/mbp/Documents/my-project/python-snippets/notebook/data/dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
#
# [change directory]
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
#
# [set target path 1 (after chdir)]
# target_path_1: target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2 (after chdir)]
# target_path_2: ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
ターミナルでカレントディレクトリを移動して同じスクリプトファイルを実行した結果は以下の通り。異なる場所から実行しても同じファイルを読み出せているのが確認できる。
cd data/src
pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
python3 file_path.py
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
# __file__: file_path.py
# basename: file_path.py
# dirname:
# abspath: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src/file_path.py
# abs dirname: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
#
# [set target path 1]
# target_path_1: target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2]
# target_path_2: ../dst/target_2.txt
# normalize : ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!
#
# [change directory]
# getcwd: /Users/mbp/Documents/my-project/python-snippets/notebook/data/src
#
# [set target path 1 (after chdir)]
# target_path_1: target_1.txt
# read target file:
# !! This is "target_1.txt" !!
#
# [set target path 2 (after chdir)]
# target_path_2: ../dst/target_2.txt
# read target file:
# !! This is "target_2.txt" !!