1. ホーム
  2. python

[解決済み] Pythonプロジェクトで相対パスを使ってファイルを読み込む

2022-11-13 05:17:07

質問

以下のような構成の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'

しかし、もし私が module.py を実行すると package ディレクトリに移動しても、エラーは発生しません。ということは、どうやら open(...) で使用される相対パスは、元のファイルが実行されている場所からの相対パスでしかないようです (すなわち __name__ == "__main__" )? 絶対パスは使いたくありません。これに対処する方法は何かありますか?

どのように解決するのですか?

相対パスは 現在の作業ディレクトリ . 相対パスが必要でない場合は、絶対パスでなければなりません。

しかし、現在のスクリプトから絶対パスを作成するために、よく使われるトリックがあります。 __file__ という特殊な属性を使うことです。

from pathlib import Path

path = Path(__file__).parent / "../data/test.csv"
with path.open() as f:
    test = list(csv.reader(f))

Python 3.4+が必要です( パスライブラリ モジュールのため) が必要です。

まだ古いバージョンに対応する必要がある場合は、次のようにすると同じ結果になります。

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))

[ 2020年版の編集です。 python3.4+が当たり前になったはずなので、jpyamsさんのコメントに触発されてpathlib版を先に移動しました] 。