4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Python] 直感的な相対importができるツール

Last updated at Posted at 2020-09-20

問題提起

  • Pythonは、上位のディレクトリや遠く離れたディレクトリからimportできない
  • Pythonの相対importは直感的ではない
    • 「そのファイル」からの相対位置指定ではない。呼び出し元ファイル(最初に実行されるpythonファイル)が変わると、相対importの参照がずれる
  • Pythonでは、自作ツールを複数のプロジェクトからimportするときのディレクトリ構成が難しい
    • 上位のディレクトリ・兄弟のディレクトリのimportが難しいため

結論

相対パス参照のパッケージをインストール

pip install relpath
from relpath import add_import_path
add_import_path("../")  # ここで、importしたいツールの場所を相対参照で指定

from my_module import some_function

詳細説明 (相対import)

relpathパッケージを利用すると、下記の例のように、
モジュールの直感的な相対importを実現できます。

from relpath import add_import_path
add_import_path("../")

from my_module import some_function

some_function()

上記の例を見ると、単にsys.path.append("../")としても動作するように思われます。
しかし、プロジェクトフォルダの階層構造が複雑で、1つのモジュールが別々の場所から使われるような場合には、sys.path.append("../")では対応できないことがあります。
そのため、相対importを実現したいときは、常にrelpathパッケージのadd_import_pathを利用することを推奨します。

その他の使い方

relpathパッケージを使うと、importに限らず、
直感的な相対パス参照が可能です。

例えば、下記のような複数のpythonファイルからなるプロジェクトを考えます。

.
`-- project_folder
    |-- parts
    |   |-- data.txt
    |   `-- script_B.py
    `-- script_A.py

script_A.pyの中では下記のように、script_B.pyを利用します。

# script_A.py

# load script_B.py
from parts.script_B import get_data

print(get_data())

この場合に、下記のコード例のように、
script_B.pyから"./data.txt"を相対的に読み込もうとすると失敗します。(注1)

(注1)
厳密には、script_A.pyからの相対パス指定をすれば読み込めますが、
呼び出し元が別の場所に変更された場合、正常に動作しなくなるので、メンテナンス性が悪くなります。
これを回避するため、relpathパッケージの利用を推奨します。

# script_B.py

def get_data():
    with open("./data.txt", "r") as f:  # -> FileNotFoundError: [Errno 2] No such file or directory: './data.txt'
        return f.read()

そこで、relpathパッケージを使って下記のように書くと、
"./data.txt"を相対的に読み込めるようになります。(注2)

# script_B.py

from relpath import rel2abs

def get_data():
    with open(rel2abs("./data.txt"), "r") as f:  # -> NO ERROR!!
        return f.read()

(注2)
相対パスに関するpythonの仕様は、必ずしも間違いというわけではありません。
pythonの仕様(相対パスの指定が、記述するファイルの場所に関わらず、常に最初の呼び出し元を基準として解釈される仕様)には、
プログラムを開発する中でもしファイル読み込み等の命令を記述する場所(ファイル)が変更になった場合でも、
パス指定方法の変更が不要になるという利点があります。
relpathパッケージは、pythonの仕様の他に、プログラマーにもう一つの選択肢を与える手段に過ぎないので、
状況に応じて利用の要否を検討することを推奨します。

参考

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?