はじめに
Python で以下のようなディレクトリ構造のとき, app/hoge.py と test/fuga.py 間で相対パスを使いたい時の備忘録です.
ディレクトリ構造
root
├── app
│ └── hoge.py
└── test
├── __init__.py
└── fuga.py
結論
以下の手順で,hoge.py から fuga.py のクラスをインポートして使用することができます.
ソースコード
import sys
sys.path.append('../')
from test import Fuga
def main():
Fuga.greeding()
if __name__ == "__main__":
main()
from .fuga import *
class Fuga:
@staticmethod
def greeding():
print("Hello from Fuga!")
コマンド
$ cd ./app
$ python3 hoge.py
事前知識
相対パス
相対パスは,カレントディレクトリを.
,現在の階層から1つ上の階層を..
で表記することができます.app がカレントディレクトリの場合,fuga.py は ../test/fuga.py
と表せます.
__init__.py
__init__.py
をディレクトリ内に作成すると,そのディレクトリがパッケージとして認識されます.
sys.path.append
sys.pathは、Pythonがモジュールやパッケージを検索する際に使用するディレクトリのリストです。Pythonはimport文を実行するとき、このリストに含まれるディレクトリを順番に検索し、最初に見つかったモジュールをインポートします。つまり親ディレクトリへのpathはsys.pathにないためエラーになります.(次項参照)
注意
Pythonのimport文では,hoge.py から fuga.py を呼び出そうとした時 from ..test import Fuga
のように表記したくなりますが,ImportError: attempted relative import with no known parent package
エラーが発生します.
これは,スクリプトを直接実行する場合,Pythonがそのスクリプトの親パッケージを認識しないためです.
Pythonはセキュリティの問題で,認識しないようにしているそう...
この問題を回避するために,sys.path
を使って親ディレクトリ(ここでいうroot)を追加します.それにより,子ディレクトリ(ここでいう/app)から親を認識できるようにします.
詳細説明
hoge.py
sys.path.append('../')
を使って親ディレクトリをパスに追加することで,test パッケージをインポートできるようにします.
rootディレクトリからは/test, /app
が見えるためインポートできるようになります.
その後,from test import Fuga
で fuga.py からクラスをインポートします.
※ from ディレクトリ名 import クラス名
に注意してください.
ファイル名(fuga)とクラス名(Fuga)の間違いで悩んでたことがあります.
__init__.py
このファイルは,test ディレクトリをパッケージとして認識させるために必要です.
__init__.py
ファイル内で fuga.py をインポートします.
fuga.py
クラス Fuga を定義します.このクラスには,greeding という静的メソッドが含まれており,"Hello from Fuga!"
と出力します.
実行方法
app ディレクトリに移動して hoge.py を実行します.これにより,hoge.py が親ディレクトリ ..
をパスに追加し,test パッケージから Fuga クラスを正しくインポートできるようになります.
$ cd ./app
$ python3 hoge.py
実行結果
Hello from Fuga!
参考