Supposons que j'ai un projet python structuré comme suit:
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)
Lorsque j'exécute main.py
, l'erreur suivante apparaît:
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'
Cependant, si je lance module.py
à partir du répertoire package
, je ne reçois aucune erreur. Il semble donc que le chemin relatif utilisé dans open(...)
ne soit relatif qu’à l’emplacement d’exécution du fichier d’origine (i.e __== "__main__"
)? Je ne veux pas utiliser de chemins absolus. Quels sont les moyens de faire face à cela?
Les chemins relatifs sont relatifs à répertoire de travail actuel . Si vous ne voulez pas que votre chemin soit, il doit être absolu.
Mais il existe une astuce souvent utilisée pour créer un chemin absolu à partir du script actuel: utilisez son attribut spécial __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))
_
Remarque: à partir de python 3.4, ___file__
_ est toujours absolu pour les modules importés et vous pouvez supprimer la partie _os.path.abspath
_ dans cet exemple. Non pas que cela soit strictement nécessaire, mais cela évite des surprises si vous modifiez le répertoire de travail en cours à un moment donné et que votre module a été importé en utilisant un chemin relatif.
Pour 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)]