Lesen der Datei unter Verwendung des relativen Pfads im Python-Projekt

78

Angenommen, ich habe ein Python-Projekt, das wie folgt aufgebaut ist:

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)

Beim Ausführen wird main.pyfolgende Fehlermeldung angezeigt:

 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'

Wenn ich jedoch module.pyaus dem packageVerzeichnis laufe, erhalte ich keine Fehler. Es scheint also, dass der relative Pfad, in dem verwendet open(...)wird, nur relativ zu dem ist, von dem aus die Ursprungsdatei ausgeführt wird (dh __name__ == "__main__")? Ich möchte keine absoluten Pfade verwenden. Wie kann man damit umgehen?

pbreach
quelle
4
Nebenbei zitiert PEP8: „Relative Importe für Intra-Package-Importe werden dringend empfohlen. Verwenden Sie für alle Importe immer den absoluten Paketpfad. “ Hier , from package.module import test.
Spektren

Antworten:

114

Relative Pfade sind relativ zum aktuellen Arbeitsverzeichnis . Wenn Sie nicht möchten, dass Ihr Weg ist, muss er absolut sein.

Es gibt jedoch einen häufig verwendeten Trick, um einen absoluten Pfad aus dem aktuellen Skript zu erstellen: Verwenden Sie das __file__spezielle Attribut:

from pathlib import Path

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

Dies erfordert Python 3.4+ (für das Pathlib- Modul).

Wenn Sie ältere Versionen weiterhin unterstützen müssen, können Sie dasselbe Ergebnis erzielen mit:

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 edit: python3.4 + sollte jetzt die Norm sein, also habe ich zuerst die Pathlib-Version verschoben, die von jpyams 'Kommentar inspiriert wurde]

Spektren
quelle
17
Wenn Sie Python 3.4+ verwenden, können Sie natürlich auch pathlib.Path verwenden :Path(__file__).parent.resolve()
jpyams
30

Für 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)]
aksh1618
quelle
3

Meine Python-Version ist Python 3.5.2 und die in der akzeptierten Antwort vorgeschlagene Lösung hat bei mir nicht funktioniert. Ich habe immer noch einen Fehler erhalten

FileNotFoundError: [Errno 2] No such file or directory

als ich my_script.pyvom Terminal rannte . Obwohl es gut funktioniert hat, als ich Run / Debug-Konfigurationen von PyCharm IDE (PyCharm 2018.3.2 (Community Edition)) ausgeführt habe.

Lösung :

anstatt zu verwenden:

my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_path 

Wie in der akzeptierten Antwort vorgeschlagen, habe ich verwendet:

my_path = os.path.abspath(os.path.dirname(os.path.abspath(__file__))) + some_rel_dir_path

Erläuterung : Durch Ändern os.path.dirname(__file__)in wird os.path.dirname(os.path.abspath(__file__)) das folgende Problem behoben:

Wenn wir unser Skript so ausführen: python3 my_script.py Die __file__Variable hat nur den Zeichenfolgenwert "my_script.py", ohne dass der Pfad zu diesem bestimmten Skript führt. Aus diesem Grund gibt die Methode dirname(__file__)eine leere Zeichenfolge "" zurück. Das ist auch die Resonanz, warum my_path = os.path.abspath(os.path.dirname(__file__)) + some_rel_dir_patheigentlich das gleiche ist wie my_path = some_rel_dir_path. Folglich FileNotFoundError: [Errno 2] No such file or directorywird angegeben, wenn versucht wird, die openMethode zu verwenden , da es kein Verzeichnis wie "some_rel_dir_path" gibt.

Das Ausführen eines Skripts aus der PyCharm-IDE Das Ausführen / Debuggen von Konfigurationen funktionierte, weil es einen Befehl ausführt python3 /full/path/to/my_script.py(wobei "/ full / path / to" von uns in der Variablen "Arbeitsverzeichnis" in Ausführen / Debuggen von Konfigurationen angegeben wird), anstatt genau python3 my_script.pywie bei uns Führen Sie es vom Terminal aus.

Hoffe das wird nützlich sein.

kaspiotr
quelle
2
Es ist in der Tat eine Einschränkung. Es ist so ungewöhnlich, Skripte explizit auszuführen, dass Sie anscheinend die ersten sind, die dies bemerken (normalerweise würden Sie sie #!/usr/bin/env pythonan die Spitze setzen, sie als ausführbar markieren und als ausführen ./myscript.py). Die pathlib.PathVersion hat dieses Gotcha jedoch nicht, da es wahrscheinlich eine bessere Option seit Python3.4 ist.
Spektren
1

Das hat bei mir funktioniert.

with open('data/test.csv') as f:

 
Programmierer
quelle
0

Versuchen

with open(f"{os.path.dirname(sys.argv[0])}/data/test.csv", newline='') as f:
Axel Schneider
quelle
0

Ich wurde gedonnert, als der folgende Code funktionierte.

import os

for file in os.listdir("../FutureBookList"):
    if file.endswith(".adoc"):
        filename, file_extension = os.path.splitext(file)
        print(filename)
        print(file_extension)
        continue
    else:
        continue

Also habe ich die Dokumentation überprüft und es heißt:

In Version 3.6 geändert: Akzeptiert ein pfadähnliches Objekt.

pfadartiges Objekt :

Ein Objekt, das einen Dateisystempfad darstellt. Ein pfadartiges Objekt ist entweder ein str oder ...

Ich habe ein bisschen mehr gegraben und das Folgende funktioniert auch:

with open("../FutureBookList/file.txt") as file:
   data = file.read()
Blue Ray
quelle