1089 Stimmen

Importieren von Modulen aus dem übergeordneten Ordner

Ich verwende Python 2.5.

Dies ist mein Ordnerbaum:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(Ich habe auch __init__.py in jedem Ordner, hier aus Gründen der Lesbarkeit weggelassen)

Wie importiere ich die nib Modul aus dem Inneren des life Modul? Ich hoffe, dass es möglich ist, ohne an sys.path herumzubasteln.

Hinweis: Das Hauptmodul, das ausgeführt wird, befindet sich in der ptdraft Ordner.

1 Stimmen

Wie ist Ihr PYTHONPATH eingestellt?

2 Stimmen

Ross: Ich habe es mir angesehen. Was soll ich dagegen tun? Ich habe bereits eine __init__.py . S.Lott: Ich weiß nicht, wie ich das überprüfen kann...

4 Stimmen

Echo $PYTHONPATH aus der Shell; import sys; print sys.path aus Python heraus. docs.python.org/tutorial/

753voto

f3lix Punkte 28602

Sie können relative Importe verwenden (Python >= 2.5):

from ... import nib

(Was ist neu in Python 2.5) PEP 328: Absolute und relative Importe

EDIT : einen weiteren Punkt '.' hinzugefügt, um zwei Pakete nach oben zu gehen

311 Stimmen

ValueError: Attempted relative import in non-package

24 Stimmen

@endolith: Sie müssen in einem Paket sein, d.h. Sie müssen eine init .py-Datei.

60 Stimmen

Versuchter relativer Import über das Toplevel-Paket hinaus

518voto

np8 Punkte 19969

Eine ähnliche Antwort habe ich auch auf die Frage nach Importen aus Geschwisterpaketen gegeben. Sie können es sehen aquí .

Lösung ohne sys.path Hacks

Zusammenfassung

  • Packen Sie den Code in einen Ordner (z. B. packaged_stuff )
  • Erstellen einer setup.py Skript, in dem Sie Folgendes verwenden setuptools.setup() .
  • Pip installiert das Paket im bearbeitbaren Zustand mit pip install -e <myproject_folder>
  • Importieren mit from packaged_stuff.modulename import function_name

Einrichtung

Ich gehe von der gleichen Ordnerstruktur wie in der Frage aus

.
 ptdraft
     __init__.py
     nib.py
     simulations
         __init__.py
         life
             __init__.py
             life.py

Ich rufe die . den Root-Ordner, und in meinem Fall befindet er sich in C:\tmp\test_imports .

Schritte

  1. Hinzufügen einer setup.py in den Root-Ordner -- Der Inhalt des Ordners setup.py kann einfach sein

    from setuptools import setup, find_packages
    
    setup(name='myproject', version='1.0', packages=find_packages())

Im Grunde genommen "jeder" setup.py funktionieren würde. Dies ist nur ein minimales Arbeitsbeispiel.

  1. Verwenden Sie eine virtuelle Umgebung

Wenn Sie mit virtuellen Umgebungen vertraut sind, aktivieren Sie eine und fahren Sie mit dem nächsten Schritt fort. Die Nutzung von virtuellen Umgebungen ist nicht absolut erforderlich, aber sie werden wirklich Ihnen auf lange Sicht helfen (wenn Sie mehr als 1 Projekt haben ). Die grundlegendsten Schritte sind (im Stammordner ausgeführt)

  • Virtuelle Umgebung erstellen
    • python -m venv venv
  • Virtuelle Umgebung aktivieren
    • . venv/bin/activate (Linux) oder ./venv/Scripts/activate (Sieg)
  • Deaktivieren der virtuellen Umgebung
    • deactivate (Linux)

Um mehr darüber zu erfahren, googeln Sie einfach nach "python virtualenv tutorial" oder ähnlichem. Wahrscheinlich brauchen Sie nie andere Befehle als das Erstellen, Aktivieren und Deaktivieren.

Sobald Sie eine virtuelle Umgebung erstellt und aktiviert haben, sollte Ihre Konsole den Namen der virtuellen Umgebung in Klammern anzeigen

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
  1. Pip-Installation Ihres Projekts im bearbeitbaren Zustand

Installieren Sie Ihr Top-Level-Paket myproject mit pip . Der Trick besteht darin, die -e Flagge, wenn Sie die Installation durchführen. Auf diese Weise wird es in einem bearbeitbaren Zustand installiert, und alle an den .py-Dateien vorgenommenen Änderungen werden automatisch in das installierte Paket aufgenommen.

Führen Sie im Root-Verzeichnis

pip install -e . (beachten Sie den Punkt, er steht für "aktuelles Verzeichnis")

Sie können auch sehen, dass es installiert ist, indem Sie pip freeze

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0
  1. Importieren durch Voranstellen von mainfolder zu jeder Einfuhr

In diesem Beispiel ist die mainfolder wäre ptdraft . Dies hat den Vorteil, dass es nicht zu Namenskollisionen mit anderen Modulnamen (aus der Python-Standardbibliothek oder Modulen von Drittanbietern) kommt.


Beispiel für die Verwendung

nib.py

def function_from_nib():
    print('I am the return value from function_from_nib!')

Leben.py

from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

Leben.py ausführen

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!

1 Stimmen

Warum funktioniert das? Wird der PYTHONPATH hinter den Kulissen irgendwie verändert?

0 Stimmen

Ihre PYTHONPATH-Variable bleibt dabei erhalten. Sie installieren Ihren Python-Code einfach mit pip (in einem bearbeitbaren Zustand).

1 Stimmen

Und wie läuft der Installationsprozess ab? Nimmt er nicht den Root-Ordner in den Pythonpfad auf? Wie hilft es Python, das Modul nib.py zu finden, wenn in life.py darauf verwiesen wird?

479voto

Remi Punkte 19243

Relative Einfuhren (wie in from .. import mymodule ) funktionieren nur in einem Paket. So importieren Sie "mymodule", das sich im übergeordneten Verzeichnis Ihres aktuellen Moduls befindet:

import os
import sys
import inspect

currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0, parentdir) 

import mymodule

bearbeiten : die __file__ Attribut ist nicht immer gegeben. Anstelle der Verwendung von os.path.abspath(__file__) Ich habe nun vorgeschlagen, das Modul inspect zu verwenden, um den Dateinamen (und den Pfad) der aktuellen Datei zu ermitteln

194 Stimmen

Etwas Kürzeres: sys.path.insert(1, os.path.join(sys.path[0], '..'))

9 Stimmen

Gibt es einen Grund, sys.path.append() anstelle von insert zu vermeiden?

3 Stimmen

@Tyler - Es kann eine Rolle spielen, ob irgendwo anders dann die parentdir sondern in einem der Pfade, die bereits in sys.path gibt es ein weiteres Modul mit dem Namen "mymodule". Das Einfügen des parentdir als erstes Element der Datei sys.path Liste stellt sicher, dass das Modul von parentdir wird stattdessen importiert.

155voto

hasen Punkte 154413

Es scheint, dass das Problem nicht damit zusammenhängt, dass sich das Modul in einem übergeordneten Verzeichnis oder ähnlichem befindet.

Sie müssen das Verzeichnis hinzufügen, das Folgendes enthält ptdraft zu PYTHONPATH

Sie sagten, dass import nib mit Ihnen gearbeitet haben, bedeutet das wahrscheinlich, dass Sie ptdraft selbst (nicht sein Elternteil) zu PYTHONPATH.

64 Stimmen

Alles zu pythonpath hinzuzufügen ist keine gute Lösung, wenn man mit vielen Paketen arbeitet, die nie wiederverwendet werden sollen.

7 Stimmen

@JasonCheng: Warum sind sie dann Pakete ?

18 Stimmen

Für mich hat sich diese Antwort bewährt. Um es jedoch noch deutlicher zu machen, besteht das Verfahren darin import sys und dann sys.path.append("..\<parent_folder>")

140voto

Shinbero Punkte 1241

Sie können den vom Betriebssystem abhängigen Pfad im "Modulsuchpfad" verwenden, der in sys.path . Sie können also einfach ein übergeordnetes Verzeichnis wie folgt hinzufügen

import sys
sys.path.insert(0,'..')

Wenn Sie ein Eltern-Eltern-Verzeichnis hinzufügen möchten,

sys.path.insert(0,'../..')

Dies funktioniert sowohl in Python 2 als auch in Python 3.

24 Stimmen

Dies bezieht sich auf die aktuell Verzeichnis, nicht einmal notwendigerweise dasjenige, das das Hauptskript enthält.

1 Stimmen

Diese Methode funktioniert in PyCharm, aber nicht in VS Code.

0 Stimmen

Hat bei mir super funktioniert! Danke! ... aber ich brauchte sibling dir, also war meine Lösung sys.path.insert(0,'../sibling_dir')

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X