静かなる名辞

pythonとプログラミングのこと



【python】実行スクリプトからの相対パスでファイルを開く


 pythonのファイルオープンの際のカレントディレクトリは実行時のshellのカレントディレクトリを引き継ぐ仕様なので(たしか)、スクリプト基準の相対パスだと思っていると悲しい思いをします。

 具体的にはこんな感じです。

$ tree hoge
hoge
├── aaa.txt
└── test1.py

0 directories, 2 files
$ cd hoge
$ cat aaa.txt 
aaa
$ cat test1.py 
with open("aaa.txt") as f:
    print(f.read())
$ python test1.py 
aaa

$ cd ..
$ python hoge/test1.py 
Traceback (most recent call last):
  File "hoge/test1.py", line 1, in <module>
    with open("aaa.txt") as f:
FileNotFoundError: [Errno 2] No such file or directory: 'aaa.txt'

 これで動くと嬉しかったのだが、動かないのです。

 対策として、スクリプトの絶対パスを拾って動かす方法……がqiitaの記事にありました。

実行スクリプト名は__file__で取得できる.
これとos.pathモジュールを組み合わせて,実行スクリプトから相対パスでファイルにアクセスする.

base = os.path.dirname(os.path.abspath(__file__))
name = os.path.normpath(os.path.join(base, '../local/local_db'))

実行スクリプトからの相対パスでファイルにアクセスする. - Qiita

 面倒くさ・・・。

 ん、それならいっそカレントディレクトリを__file__に張り替えれば良いのでは。それで後から元に戻せば副作用はない(マルチスレッドでもない限りは)。

$ cat hoge/test2.py 
import os

tmp = os.getcwd()
os.chdir(os.path.dirname(os.path.abspath(__file__)))
with open("aaa.txt") as f:
    print(f.read())
os.chdir(tmp)
$ python hoge/test2.py 
aaa

$ cd hoge
$ python test2.py 
aaa

 実行スクリプトのディレクトリの絶対パスを拾うために結局os.path.abspathとか使ってるし、あまりスマートにはならなかったですね。

 ちなみに、python3.4以降はこんなのもあるらしいですが、もはや魔法の呪文じみてる気が・・・(pathlibを使いこなせれば大丈夫なのでしょうけど)。

from pathlib import Path
print(Path(__file__).resolve().parent)

スクリプトの存在するディレクトリーの絶対パスを取得する - Qiita