見出し画像

Pythonのパス指定で手こずった話

1. はじめに

 前回にも同様の記事を書いたが、筆者はちょっとした便利ツールをPythonで記述することが多い。

  Pythonはライブラリも多く、簡単なツールの作成には適しているが、躓くこともある。今回は、その中でもPythonのパス指定の話をまとめる。

2. 絶対パスと相対パス

 まず、「絶対パス」「相対パス」について整理する。OS上でのファイル管理は、階層構造となっている。そのため、実行するには目的のファイルの位置を指示する必要がある。この「位置」のことを、IT用語では「パス」と呼んでいる。パスの指定方法には、絶対パスと相対パスの2種類あり、どちらかを使ってファイルの場所を指定する。

 IT業界以外の人に「パス」が……と話したところ、「パスって何ですか?」と言われたことがある。

2.1 絶対パスとは

 絶対パスとは、ファイルの位置を最初から最後まで記述する指定方法である。例えば、以下のフォルダ構成を考える。

Cドライブ
┣Users
   ┣Username
      ┣Desktop
         ┣テスト
            ┣Data.txt 

 上記の通り、テストフォルダ内にあるData.txtのパスを知りたいとする。この場合、データのパスは以下となる(Windowsの場合)。

C:\Users\Username\Desktop\テスト\Data.txt

 上記の通り、絶対パスでは、最初から最後までの位置を指定していることが分かる。なお、絶対パスのことをフルパスと呼ぶ。

2.2 相対パスとは

 相対パスは、現在いるパスを起点とした位置のことである。例えば、以下のフォルダから考える。

Cドライブ
┣Users
   ┣Username
      ┣Desktop
         ┣テスト
            ┣Data.txt 

 上記のフォルダ階層において、DesktopからData.txtの相対パスを考えると、以下のようになる。

/テスト/Data.txt

 上記のように、相対パスでは、あるファイルの起点からの位置を指定する。Desktopの階層からData.txtにたどり着くには、「テスト」→「Data.txt」の順番にたどる。よって、この場合、「/テスト/Data.txt」と指定する。

3. 事象の整理

 2項を踏まえつつ、しくじった話を整理する。

3.1 プログラムのイメージ

 プログラムのイメージを以下に示す(詳細は端折っている)。

 #プログラムがあるパスを取得 
currentPath = os.getcwd() #プログラムがあるパス /Log/Log.txtを読み込みファイル用のパスに設定
readFilePath = currentPath + "/Log/" + "Log.txt" #ファイルを読み込む 
file = open(readFilePath, "r", encoding="utf_8")

 以下に要約を示す。
(1) 実行したプログラムがあるパスを取得する。
(2) 取得したパスのLogフォルダ内のLog.txtを読み込み用のファイルとして設定する。
(3) 設定したファイルを開く

3.2 問題なく動作する

 当初、筆者は問題ないプログラムであると思っていた。よって、コマンドラインからプログラムがある階層に移動し、以下のコマンドを実行した。

python program.py

 実行すると、筆者の意図した出力結果となったが、実は問題があった。

3.3 プログラムとは別の階層から動作を確認する

 このプログラムを別の階層から実行するとどうだろうか。例えば、以下のように実行する。

python myfolder/program.py

 上記は、「myfolder」というフォルダからプログラムを実行したコマンドである。このコマンドからプログラムを実行すると、残念ながら下記のようなエラーメッセージが現れ、動作しないことが分かった。

FileNotFoundError: [Errno 2] No such file or directory:

 「No such file or directory」と書いてあるため、「ファイルかディレクトリが見つからない」とエラーが出ている。

4. しくじった原因

 しくじった原因は、パスの取得方法であった。

currentPath = os.getcwd()

 上記の「os.getcwd()」は、実行するプログラムのパスではなく、現在のパスを取得する関数だった。結果、プログラムがない別の階層から実行すると、対象の読み込み用のパスにたどり着かずにエラーとなる。

 例えば、以下の階層を持ったフォルダがあると考える。
C:\Users\user\Desktop\myfolder\program.py

 実行したいプログラムがprogram.pyと考えると、以下の違いがある。

(1) C:\Users\user\Desktop\myfolderからの実行
 このフォルダから以下のコマンドを実行する。

python program.py

出力するパス
C:\Users\user\Desktop\myfolder

(2) C:\Users\user\Desktopからの実行
 プログラムのないDesktopフォルダから以下のコマンドを実行する。

python myfoloder/program.py

出力するパス
C:\Users\user\Desktop\

 2つの出力結果が異なることが分かる。つまり、原因は、「プログラムがあるパスを取得するはずが、コマンドライン上の現在のディレクトリを取得してしまった」であった。

5. どうすればよかったのか

 4項の問題から、パスの取得方法を「os.getcwd」から「os.path.dirname(__file__)」に変更した。詳細を下記に示す。

 #プログラムがあるパスを取得 
curPath = os.path.dirname(__file__) #プログラムがあるパス /Log/Log.txtを読み込みファイル用のパスに設定
readFilePath = currentPath + "/Log/" + "Log.txt" #ファイルを読み込む 
file = open(readFilePath, "r", encoding="utf_8")

 このように指定することで、実行するプログラムのパスを取得できる。結果、目的のファイルを異なるディレクトリにいても読み込むことができる。

6. おわりに

 Pythonは、ライブラリも豊富で、ちょっとしたツールを作る際にはちょうどいいが、躓くことも少なくない。

 今回は、Pythonのパス指定で躓いた話をまとめた。パスの指定方法は、簡単に見えるが、ちょっとした落とし穴もあるので気を付けてほしい。

この記事が気に入ったらサポートをしてみませんか?