note.nkmk.me

Pythonで実行中のファイルの場所(パス)を取得する__file__

Posted: 2018-07-22 / Modified: 2020-08-10 / Tags: Python, ファイル処理

Pythonで実行中のスクリプトファイル.pyの場所(パス)を取得するには__file__を使う。実行中のファイルの場所を基準にほかのファイルを読み込んだりする場合に便利。

__file__で得られるのはpython3コマンド(環境によってはpythonコマンド)の実行時に指定したパス。相対パスで指定した場合は相対パス、絶対パスで指定した場合は絶対パスが返される。

以下の内容について説明する。

  • os.getcwd()__file__
  • 実行中のファイルのファイル名、ディレクトリ名を取得
  • 実行中のファイルの絶対パスを取得
  • 実行中のファイルの場所を基準にほかのファイルを読み込み
  • カレントディレクトリを実行中のファイルのディレクトリに移動
  • 実行時のカレントディレクトリに依存せず同じ処理が可能

カレントディレクトリ(作業ディレクトリ)の取得、変更については以下の記事を参照。

なお、Jupyter Notebook(.ipynb)では__file__は使えないので注意。Jupyter Notebookを起動させたディレクトリによらず、.ipynbがあるディレクトリがカレントディレクトリとして実行される。コードの中でos.chdir()を使ってカレントディレクトリを変更することは可能。

スポンサーリンク

os.getcwd()と__file__

以下のディレクトリで作業するものとする。Windowsではpwdではなくdirコマンドでカレントディレクトリを確認できる。

pwd
# /Users/mbp/Documents/my-project/python-snippets/notebook

下の階層(data/src)に以下の内容のPythonのスクリプトファイル(file_path.py)を作成。

import os

print('getcwd:      ', os.getcwd())
print('__file__:    ', __file__)
source: file_path.py

python3コマンド(環境によってはpythonコマンド)でスクリプトファイルのパスを指定して実行する。

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コマンドで指定したパスが取得できている。

__file__にはpython3(またはpython)コマンドで指定したパスがそのまま格納される。上の例では相対パスで指定したので相対パスが返されているが、絶対パスで指定した場合は絶対パスが返される。

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

以降の例では同じスクリプトファイル(file_path.py)にコードを追記して上記のディレクトリから相対パスで指定して実行するものとする。

なお、絶対パスで指定した場合も以降の説明と同じコードで実行中のファイルの場所を基準にほかのファイルを読み込んだりする処理が可能。絶対パスで指定して実行した結果は最後にまとめて示す。

実行中のファイルのファイル名、ディレクトリ名を取得

実行中のファイルのファイル名、ディレクトリ名を取得するには、標準ライブラリのos.pathモジュールの関数os.path.basename(), os.path.dirname()を使う。

print('basename:    ', os.path.basename(__file__))
print('dirname:     ', os.path.dirname(__file__))
source: file_path.py

実行結果。

# basename:     file_path.py
# dirname:      data/src

os.pathモジュールの関数os.path.basename(), os.path.dirname()などについての詳細は以下の記事を参照。

実行中のファイルの絶対パスを取得

__file__で相対パスを取得した場合はos.path.abspath()で絶対パスに変換できる。ディレクトリも絶対パスで取得可能。

print('abspath:     ', os.path.abspath(__file__))
print('abs dirname: ', os.path.dirname(os.path.abspath(__file__)))
source: file_path.py

実行結果。

# 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()で連結する。

実行中のファイルと同じディレクトリのファイルを読み込む場合はファイル名のみを連結すればOK。

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())
source: file_path.py

実行結果。

# [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())
source: file_path.py

実行結果。

# [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()で移動していることが確認できる。

print('[change directory]')
os.chdir(os.path.dirname(os.path.abspath(__file__)))
print('getcwd:      ', os.getcwd())
source: file_path.py

実行結果。

# [change directory]
# getcwd:       /Users/mbp/Documents/my-project/python-snippets/notebook/data/src

カレントディレクトリを移動してしまえば、ファイルを読み込むときに実行中のファイルのディレクトリと連結する必要はない。実行中のファイルのディレクトリからの相対パスをそのまま指定すればOK。

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())
source: file_path.py

実行結果。

# [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" !!
スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事