モジュールインポートとsubprocess.runを用いてPythonファイルを参照する方法を理解する

IT

はじめに

本記事では Python ファイル内で他のファイルを参照するときのパスについて、モジュールのインポートとsubprocess.runを例に説明します。

環境

$ python -V
Python 3.10.8

使用するディレクトリ構造とPythonファイル

ディレクトリ構造は以下の通りです。

project/
├── main.py
└── lib/
    ├── helper.py
    └── script.py

helper.py

def some_function():
    return 'Hello'

script.py

def some_script_function():
    print("Hello from script")


some_script_function()

モジュールの import

モジュールを import する場合、import を行うファイルからの相対パスで記述します。

main.py

import os

from lib.helper import some_function


def main():
    result = some_function()
    print(result)


if __name__ == "__main__":
    print("Current directory:", os.getcwd())
    main()

カレントディレクトリが変わっても、正しく動作します。

$ python main.py
Current directory: /python_path_sample/project
Hello

$ python project/main.py
Current directory: /python_path_sample
Hello

subprocess.run

subprocess.runでコマンドを実行する場合は、絶対パスか、実行時のカレントディレクトリ(呼び出し元ファイルのディレクトリではない)からの相対パスで書く必要があります。
そのため以下では初めに main.py のディレクトリを絶対パスで取得(root_dir)し、それを起点に呼び出すファイルの絶対パスを生成しています。

main.py

import os
import subprocess


def main():
    root_dir = current_dir = os.path.dirname(__file__)
    filefile_path = os.path.join(root_dir, "lib", "script.py")
    subprocess.run(["python3", filefile_path])


if __name__ == "__main__":
    print("Current directory:", os.getcwd())
    main()

カレントディレクトリが変わっても、正しく動作します。

$ python main.py
Current directory: /python_path_sample/project
Hello from script

$ python project/main.py
Current directory: /python_path_sample
Hello from script

※参考
ちなみに、以下のように、main.pyからの相対パスで実行すると、カレントディレクトリが変わった時にエラーになります。
main.py

import os
import subprocess


def main():
    subprocess.run(["python3", "lib/script.py"])


if __name__ == "__main__":
    print("Current directory:", os.getcwd())
    main()
$ python main.py
Current directory: /python_path_sample/project
Hello from script

$ python project/main.py
Current directory: /python_path_sample
/opt/homebrew/bin/python3: can't open file '/python_path_sample/lib/script.py': [Errno 2] No such file or directory

おわりに

本記事では、Pythonファイル内で他のファイルを参照する方法について、モジュールのインポートとsubprocess.runを例に説明しました。モジュールのインポートでは相対パスを用いることで、カレントディレクトリに依存せずにファイルを参照できます。一方、subprocess.runではカレントディレクトリに依存しないようにするため、呼び出し元ファイルのディレクトリを基準に絶対パスを生成する方法を紹介しました。これらの方法を利用することで、カレントディレクトリが変わっても正しく動作するPythonプロジェクトを構築できます。
この記事がどなたかの参考になれば幸いです。

参考

コメント