次のような構造のpythonプロジェクトがあるとします。
project
/data
test.csv
/package
__init__.py
module.py
main.py
__init__.py
:
from .module import test
module.py
:
import csv
with open("..data/test.csv") as f:
test = [line for line in csv.reader(f)]
main.py
:
import package
print(package.test)
main.py
を実行すると、次のエラーが表示されます。
C:\Users\Patrick\Desktop\project>python main.py
Traceback (most recent call last):
File "main.py", line 1, in <module>
import package
File "C:\Users\Patrick\Desktop\project\package\__init__.py", line 1, in <module>
from .module import test
File "C:\Users\Patrick\Desktop\project\package\module.py", line 3, in <module>
with open("../data/test.csv") as f:
FileNotFoundError: [Errno 2] No such file or directory: '../data/test.csv'
ただし、package
ディレクトリからmodule.py
を実行してもエラーは発生しません。したがって、open(...)
で使用される相対パスは、元のファイルが実行されている場所(つまり__== "__main__"
)にのみ関連しているようです。絶対パスを使用したくありません。これに対処する方法は何ですか?
相対パスは 現在の作業ディレクトリ に相対的です。あなたがあなたの道になりたくないなら、それは絶対でなければなりません。
しかし、現在のスクリプトから絶対パスを作成するためによく使用されるトリックがあります: __file__
特別な属性を使用します:
import csv
import os.path
my_path = os.path.abspath(os.path.dirname(__file__))
path = os.path.join(my_path, "../data/test.csv")
with open(path) as f:
test = list(csv.reader(f))
python 3.4から、インポートされたモジュールでは__file__
は常に絶対であり、この例ではos.path.abspath
部分をドロップできます。厳密に必要というわけではありませんが、現在の作業ディレクトリをある時点で変更し、モジュールが相対パスを使用してインポートされた場合に驚くことはありません。
Python 3.4+の場合:
import csv
from pathlib import Path
base_path = Path(__file__).parent
file_path = (base_path / "../data/test.csv").resolve()
with open(file_path) as f:
test = [line for line in csv.reader(f)]