web-dev-qa-db-fra.com

Lecture de fichier à l'aide d'un chemin relatif dans le projet python

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?

38
pbreach

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.

57
spectras

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)]
8
aksh1618