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/

95voto

Rob Ellenbroek Punkte 891

Ich weiß nicht viel über Python 2.
In Python 3 kann der übergeordnete Ordner wie folgt hinzugefügt werden:

import sys 
sys.path.append('..')

...und dann kann man daraus Module importieren

38 Stimmen

Dies funktioniert nur, wenn Ihr aktuelles Arbeitsverzeichnis so ist, dass '..' führt zu dem Verzeichnis, in dem sich das betreffende Modul befindet.

65voto

Ricardo Murillo Punkte 2667

Wenn das Hinzufügen Ihres Modulordners zum PYTHONPATH nicht funktioniert hat, können Sie die sys.path Liste in Ihrem Programm, in der der Python-Interpreter nach den zu importierenden Modulen sucht, die python-dokumentation sagt:

Wenn ein Modul namens Spam importiert wird, sucht der Interpreter zunächst nach einem eingebauten Modul mit diesem Namen. Wenn er nicht gefunden wird, sucht er nach einer Datei namens spam.py in einer Liste von Verzeichnissen, die durch die Variable sys.path angegeben wird. sys.path wird von diesen Orten aus initialisiert:

  • das Verzeichnis, das das Eingabeskript enthält (oder das aktuelle Verzeichnis).
  • PYTHONPATH (eine Liste von Verzeichnisnamen, mit der gleichen Syntax wie die Shell-Variable PATH).
  • die installationsabhängige Voreinstellung.

Nach der Initialisierung können Python-Programme die sys.path . Das Verzeichnis, das das auszuführende Skript enthält, wird an den Anfang des Suchpfads gesetzt, noch vor dem Pfad der Standardbibliothek. Dies bedeutet, dass Skripte in diesem Verzeichnis anstelle von gleichnamigen Modulen im Bibliotheksverzeichnis geladen werden. Dies ist ein Fehler, es sei denn, die Ersetzung ist beabsichtigt.

Wenn Sie dies wissen, können Sie in Ihrem Programm Folgendes tun

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft

8 Stimmen

Ihre Antwort ist gut, aber sie funktioniert vielleicht nicht immer und ist nicht sehr tragbar. Wenn das Programm an einen neuen Ort verschoben wurde, /path/to/ptdraft bearbeitet werden müssen. Es gibt auch Lösungen, die das aktuelle Verzeichnis der Datei ermitteln und sie auf diese Weise aus dem übergeordneten Ordner importieren.

1 Stimmen

@Edward Was sind das für Techniken?

1 Stimmen

@Shuklaswag zum Beispiel, die Antwort stackoverflow.com/questions/714063/ .

39voto

Edward Punkte 994

Hier ist eine Antwort, die einfach ist, damit Sie sehen können, wie sie funktioniert, klein und plattformübergreifend.
Es verwendet nur eingebaute Module ( os , sys et inspect ), sollte also funktionieren
auf jedem Betriebssystem (OS), da Python dafür ausgelegt ist.

Kürzerer Code für die Antwort - weniger Zeilen und Variablen

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

Für weniger Zeilen als diese, ersetzen Sie die zweite Zeile durch import os.path as path, sys, inspect ,
add inspect. zu Beginn von getsourcefile (Zeile 3) und entfernen Sie die erste Zeile.
- Allerdings werden dabei alle Module importiert, so dass mehr Zeit, Speicher und Ressourcen benötigt werden könnten.

Der Code für meine Antwort ( längere Version )

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

Sie verwendet ein Beispiel aus einer Stack Overflow-Antwort Wie erhalte ich den Pfad des aktuellen
Datei in Python ausführen?
um die Quelle (Dateiname) von laufendem Code mit einem eingebauten Werkzeug zu finden.

from inspect import getsourcefile  
from os.path import abspath  

Als Nächstes können Sie die Quelldatei überall dort finden, wo Sie sie haben möchten:

abspath(getsourcefile(lambda:0))

Mein Code fügt einen Dateipfad zu sys.path は、その python pfadliste
weil dies Python erlaubt, Module aus diesem Ordner zu importieren.

Nach dem Importieren eines Moduls in den Code ist es eine gute Idee, die Funktion sys.path.pop(0) in einer neuen Zeile
wenn der hinzugefügte Ordner ein Modul mit demselben Namen wie ein anderes importiertes Modul enthält
später im Programm. Sie müssen das vor dem Import hinzugefügte Listenelement entfernen, nicht andere Pfade.
Wenn Ihr Programm keine anderen Module importiert, ist es sicher, den Dateipfad nicht zu löschen, weil
nach dem Beenden eines Programms (oder dem Neustart der Python-Shell), werden alle Änderungen, die an sys.path verschwinden.

Hinweise zu einer Dateinamen-Variable

Meine Antwort verwendet nicht die __file__ um den Dateipfad/Dateinamen der laufenden
Code, denn die Nutzer hier haben ihn oft beschrieben als unzuverlässig . Sie sollten es nicht verwenden
für Module aus übergeordnetem Ordner importieren in Programmen, die von anderen Personen verwendet werden.

Einige Beispiele, wo es nicht funktioniert (Zitat aus ce Stack Overflow-Frage):

- es kann nicht sein auf einigen Plattformen zu finden - manchmal nicht der vollständige Dateipfad ist

  • py2exe hat keine __file__ Attribut, aber es gibt eine Umgehung
  • Wenn Sie von IDLE aus mit execute() Es gibt keine __file__ Attribut
  • OS X 10.6, wo ich Folgendes erhalte NameError: global name '__file__' is not defined

1 Stimmen

Ich tat dies und entfernte den neuen Pfadeintrag mit sys.path.pop(0) unmittelbar nach dem Import des gewünschten Moduls. Nachfolgende Importe gingen jedoch weiterhin an diese Stelle. Ich habe zum Beispiel app/config , app/tools y app/submodule/config . Von submodule , füge ich ein app/ zu importieren tools dann entfernen app/ und versuchen Sie zu importieren config aber ich bekomme app/config anstelle von app/submodule/config .

0 Stimmen

Ich habe herausgefunden, dass eine der tools Die Einfuhren der EU importierten auch config aus dem übergeordneten Verzeichnis. Als ich später versuchte, die sys.path.pop(0); import config innerhalb submodule in der Erwartung, dass sie app/submodule/config bekam ich tatsächlich app/config . Offensichtlich gibt Python eine im Cache gespeicherte Version eines Moduls mit demselben Namen zurück, anstatt tatsächlich die sys.path nach einem Modul mit diesem Namen. sys.path wurde in diesem Fall korrekt geändert, Python hat es nur nicht überprüft, weil das gleichnamige Modul bereits geladen war.

0 Stimmen

Ich glaube, dies ist der genaue Hinweis auf das Problem, das ich hatte: docs.python.org/3/reference/import.html#the-module-cache

38voto

itmatters Punkte 555

Die pathlib-Bibliothek (enthalten in >= Python 3.4) macht es sehr übersichtlich und intuitiv, den Pfad des Elternverzeichnisses an den PYTHONPATH anzuhängen:

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))

1 Stimmen

Ist es möglich, die init .py, um dieses Problem zu umgehen?

1 Stimmen

Danke, Eric, ich habe den verwirrenden Teil entfernt.

0 Stimmen

Import sys from pathlib import Path sys.path.append(str(Path('.').absolute().parent)))

34voto

Mike Punkte 1895

Hier ist eine allgemeinere Lösung, die das übergeordnete Verzeichnis in sys.path einschließt (funktioniert bei mir):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))

0 Stimmen

import os, sys\n sys.path.insert(0,os.path.pardir) das Gleiche, nur anders :) (keine Zeilenvorschübe in Kommentaren)

0 Stimmen

@antiveeranna, wenn Sie die os.path.pardir erhalten Sie nicht den realen Pfad des Elternteils, sondern nur den relativen Pfad von der Stelle, an der Sie die sys.path.insert()

2 Stimmen

Diese Antwort verwendet die __file__ variabel sein, die unzuverlässig (ist nicht immer der vollständige Dateipfad, funktioniert nicht auf allen Betriebssystemen usw.), wie StackOverflow-Benutzer oft erwähnt haben. Wenn Sie die Antwort so ändern, dass sie nicht mehr enthalten ist, werden weniger Probleme auftreten und die Kompatibilität ist besser. Für weitere Informationen siehe stackoverflow.com/a/33532002/3787376 .

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