Wie kann ich Importe erstellen, die immer funktionieren?

Ich kämpfe ein bisschen, um eine Arbeitsstruktur in einem meiner Projekte einzurichten. Das Problem ist, dass ich Hauptpaket und ein Unterpaket in einer solchen Struktur habe (ich habe alle unnötigen Dateien ausgelassen):

code.py mypackage/__init__.py mypackage/work.py mypackage/utils.py 

Die utils.py hat einige Utility-Code, der normalerweise nur im mypackage Paket verwendet wird.

Ich habe normalerweise einige Test-Code jede Modul-Datei, die einige Methoden des aktuellen Moduls aufruft und druckt einige Dinge zu quickcheck, wenn alles richtig funktioniert. Dieser Code wird am Ende der Datei in einem if __name__ == "__main__" -Block platziert. Also nehme ich die utils.py direkt über import utils . ZB mypackage / work.py sieht aus wie:

 import utils def someMethod(): pass if __name__ == "__main__": print(someMethod()) 

Aber jetzt, wenn ich dieses Modul im Elternpaket (zB code.py) verwende und ich es so importiere

 import mypackage.work 

Ich bekomme folgende Fehlermeldung:

 ImportError: No module named 'utils' 

Nach einigen Recherchen habe ich herausgefunden, dass dies durch Hinzufügen des mypackage/ zur PYTHONPATH Umgebungsvariable behoben werden kann, aber das fühlt sich für mich seltsam an. Gibt es keine andere Möglichkeit, dies zu beheben? Ich habe von relativen Importen gehört, aber das wird in den Python-Dokumenten über Module erwähnt

Beachten Sie, dass relative Importe auf dem Namen des aktuellen Moduls basieren. Da der Name des Hauptmoduls immer " main " ist, müssen Module, die für die Verwendung als Hauptmodul einer Python-Anwendung gedacht sind, immer absolute Importe verwenden.

Irgendwelche Vorschläge, wie ich einen if __name__ == "__main__" Abschnitt im Submodul haben kann und auch diese Datei aus dem übergeordneten Paket verwenden kann, ohne die Importe zu if __name__ == "__main__" ?

EDIT: Wenn ich einen relativen Import in work.py wie in einer Antwort zum Importieren von utils vorgeschlagen:

 from . import utils 

Ich bekomme folgende Fehlermeldung:

 SystemError: Parent module '' not loaded, cannot perform relative import 

4 Solutions collect form web for “Wie kann ich Importe erstellen, die immer funktionieren?”

Leider verwandeln sich die relativen Importe und der Direktbetrieb von Submodulen nicht.

Fügen Sie das übergeordnete Verzeichnis von mypackage zu Ihrem PYTHONPATH oder immer cd in das übergeordnete Verzeichnis, wenn Sie ein Submodul ausführen möchten.

Dann haben Sie zwei Möglichkeiten:

Verwenden Sie absolut ( from mypackage import utils ) anstelle von relativen importierungen ( from . import utils ) und führen Sie sie direkt wie zuvor aus. Der Nachteil bei dieser Lösung ist, dass Sie immer den vollqualifizierten Pfad schreiben müssen, so dass es mehr Arbeit macht, um mypackage später umzubenennen, unter anderem.

oder

Führen Sie python3 -m mypackage.utils etc. aus, um Ihre Submodule zu starten, anstatt python3 mypackage/utils.py .

Dies kann einige Zeit dauern, um sich anzupassen, aber es ist der richtige Weg (ein Modul in einem Paket ist nicht das gleiche wie ein eigenständiges Skript) und Sie können weiterhin relative Importe verwenden.

Es gibt mehr "magische" Lösungen mit __package__ und sys.path aber sie alle benötigen zusätzlichen Code an der Spitze jeder Datei mit relativen Importen, die Sie direkt ausführen möchten. Ich würde diese nicht empfehlen.

Sie sollten eine Struktur wie folgt erstellen:

 flammi88 ├── flammi88 │ ├── __init__.py │  ├── code.py │  └── mypackage │  ├── __init__.py │  ├── utils.py │  └── work.py └── setup.py 

Dann stelle dies zumindest in die setup.py:

 import setuptools from distutils.core import setup setup( name='flammi88', packages=['flammi88'], ) 

Jetzt aus dem Verzeichnis mit setup.py, laufen

 pip install -e . 

Damit wird das flammi88-Paket im Entwicklungsmodus verfügbar. Jetzt können Sie sagen:

 from flammi88.mypackage import utils 

überall. Dies ist der normale Weg, um Pakete in Python zu entwickeln, und es löst alle Ihre relativen Import-Probleme. Das heißt, Guido runzelt die Standalone-Skripte in Unterpaketen. Mit dieser Struktur würde ich die Tests in flammi88/tests/... (und sie mit zB py.test laufen lassen), aber manche Leute mögen die Tests neben dem Code behalten.

Aktualisieren:

Eine erweiterte setup.py, die externe Anforderungen beschreibt und erstellt ausführbare Dateien der Sub-Pakete, die Sie ausführen möchten, kann wie folgt aussehen:

 import setuptools from distutils.core import setup setup( name='flammi88', packages=['flammi88'], install_requires=[ 'markdown', ], entry_points={ 'console_scripts': [ 'work = flammi88.mypackage.work:someMethod', ] } ) 

Jetzt, nach Pip-Installation deines Pakets, kannst du einfach die work an der Kommandozeile eingeben.

Import utils innerhalb der work.py wie folgt:

 import mypackage.utils 

Oder wenn du einen kürzeren Namen verwenden möchtest:

 from mypackage import utils 

BEARBEITEN: Wenn Sie work.py außerhalb des Pakets ausführen work.py , dann versuchen Sie:

 try: from mypackage import utils except ImportError: import utils 

Benutzen:

 from . import utils 

Wie von Peter vorgeschlagen

In deinem Code.py solltest du:

 from mypackage import work 
  • Unbenannte überspringen, wenn eine Bedingung in SetUpClass fehlschlägt
  • Funktionen höherer Ordnung: Automatische Generierung vs manuelle Definition
  • Python3 import nicht finden Modul
  • Datei-Liste mit Glob in Python
  • Chunking Bytes (nicht Strings) in Python 2 und 3
  • Konvertieren Sie den binären Eingangsstrom in den Textmodus
  • Was sind gute Verwendungen für Python3's "Function Annotations"
  • Formatieren Sie einen String, der extra lockige Klammern hat
  • TensorFlow unter Windows installieren (Python 3.6.x)
  • Python 3.5.1 urllib hat keine Attributanfrage
  • Pip Fehler: sollte Pip, Pandas und Matplotlib aktualisieren, aber gibt Fehler zurück
  • Python ist die beste Programmiersprache der Welt.