web-dev-qa-db-de.com

Python kann mein Modul nicht finden

Ich habe ein Python-Projekt (das ich in einer Virtualenv-Umgebung laufe) und das folgende Struktur hat:

Project
├───.git
├───venv
└───src
    ├───__init__.py
    ├───mymodules
    │   ├───__init__.py
    │   ├───module1.py
    │   └───module2.py
    └───scripts
        ├───__init__.py
        └───script.py

script.py

import src.mymodules.module1
...

Ich führe das Projekt mit aktiviertem venv und aus dem Projektverzeichnis mit folgendem Befehl aus:

(venv)$ python src/scripts/script.py

Das Skript wird ausgeführt, gibt jedoch vor dem Beenden den folgenden Fehler aus:

Traceback (most recent call last):
  File "src/scripts/script.py", line 1, in <module>
    import src.mymodules.module1
ImportError: No module named src.mymodules.module1

Ich habe versucht, die Python-Shell auszuführen und zu versuchen, das Modul von dort zu importieren, und es gab keine Fehler. Ich habe _ _init__.py in jedem Verzeichnis innerhalb von src. Betrachtet Python das Arbeitsverzeichnis als src/scripts? Warum passiert das und wie kann ich src zum Arbeitsverzeichnis machen, wenn dies der Fall ist?

23
CrazyJony

Wenn Sie script.py direkt ausführen, wissen Sie im Wesentlichen nicht, dass es Teil eines Submoduls von src ist, und wissen auch nicht, wo sich ein Modul mit dem Namen src befinden könnte. Dies ist entweder in Python 2 oder 3 der Fall. 

Wie Sie wissen, findet Python Module basierend auf dem Inhalt von sys.path . Um ein Modul zu importieren, muss es sich entweder in einem Verzeichnis befinden, das in sys.path aufgeführt ist, oder in demselben Verzeichnis wie das Skript, das Sie ausführen. 

Wenn Sie python src/scripts/script.py sagen, schließt sys.path den Project/src/scripts/ ein (da sich script.py dort befindet), aber nicht Project. Da sich Project nicht im Pfad befindet, können die Module in diesem Verzeichnis (src) nicht importiert werden. 

Um das zu beheben: 

Ich gehe davon aus, dass Ihr script.py ein Einstiegspunkt für Ihr src-Modul ist (zum Beispiel ist es vielleicht das Hauptprogramm). Wenn dies wahr ist, können Sie das Problem beheben, indem Sie script.py auf die gleiche Ebene wie src verschieben:

Project
├───.git
├───venv
|───script.py       <--- script.py moves up here
└───src
    ├───__init__.py
    └───mymodules
        ├───__init__.py
        ├───module1.py
        └───module2.py

Auf diese Weise kann script.py alles in src frei importieren, aber nichts in src kann script.py importieren.

Wenn dies nicht der Fall ist und script.py wirklich ein Teil von src ist, können Sie das Argument -m von python verwenden, um script.py als Teil des src-Moduls wie folgt auszuführen: 

$ python -m src.scripts.script

Da Sie Python mitgeteilt haben, welches Modul Sie ausführen (src), wird es sich im Pfad befinden. Daher wird script.py wissen, dass es sich um ein Submodul von src handelt, und kann dann von src importiert werden. 

Seien Sie in dieser Situation jedoch vorsichtig - es besteht die Möglichkeit, einen zirkularen Import zu erstellen, falls etwas in src importiert wird src.scripts.script


Alternativ zu beiden Ansätzen können Sie den sys.path direkt in script.py ändern: 

import sys
sys.path.insert(0, '/path/to/Project') # location of src 

Während dies funktioniert, ist es normalerweise nicht meine Präferenz. Es erfordert script.py, um genau zu wissen, wie Ihr Code angeordnet ist, und kann zu Importverwirrung führen, wenn ein anderes Python-Programm versucht, script.py zu importieren. 

15
Seth
Project
├───.git
├───venv
└───src
    ├───__init__.py
    ├───mymodules
    │   ├───__init__.py
    │   ├───module1.py
    │   └───module2.py
    └───scripts
        ├───__init__.py
        └───script.py

Alternativ können Sie wie folgt in Ihre script.py importieren

import os
import sys
sys.path.append(os.path.join(os.path.dirname(__file__),'../../'))
import src.mymodules.module1

Jetzt können Sie die Datei script.py von einem beliebigen Ort aus ausführen.

e.g :
python script.py
python /path to folder/script.py
0
parthiban

Wenn Sie dieses Problem beim Umgang mit Pytest oder coverage haben. Das Hinzufügen einer __init__.py - Datei löst die meisten Fälle.

0
azzamsa

Eine andere Lösung besteht darin, den Dateinamen 'xxx (beliebiger Name) .pth' zu erstellen und Ihr Projektverzeichnis (Mutterverzeichnis Ihrer SRC) zu schreiben. Legen Sie diese Datei in '/ virtual_env/lib/pythonXX/site-packages /' ab. Auf diese Weise müssen Sie sys.path nicht in Ihr Skript importieren.

0
Guiliang Liu