Importieren von einem relativen Pfad in Python

102

Ich habe einen Ordner für meinen Clientcode, einen Ordner für meinen Servercode und einen Ordner für Code, der von ihnen gemeinsam genutzt wird

Proj/
    Client/
        Client.py
    Server/
        Server.py
    Common/
        __init__.py
        Common.py

Wie importiere ich Common.py aus Server.py und Client.py?

Drew
quelle
Siehe auch
moooeeeep

Antworten:

137

EDIT Nov 2014 (3 Jahre später):

Python 2.6 und 3.x unterstützen ordnungsgemäße relative Importe, bei denen Sie Hacking vermeiden können. Mit dieser Methode wissen Sie, dass Sie eher einen relativen als einen absoluten Import erhalten. Das '..' bedeutet, gehe in das Verzeichnis über mir:

from ..Common import Common

Als Einschränkung funktioniert dies nur, wenn Sie Ihre Python als Modul von außerhalb des Pakets ausführen . Beispielsweise:

python -m Proj

Ursprünglicher hackiger Weg

Diese Methode wird immer noch häufig in einigen Situationen verwendet, in denen Sie Ihr Paket nie "installieren". Zum Beispiel ist es bei Django-Benutzern beliebt.

Sie können Common / zu Ihrem sys.path hinzufügen (die Liste der Pfade, die Python zum Importieren von Dingen betrachtet):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) Sie erhalten nur das Verzeichnis, in dem sich Ihre aktuelle Python-Datei befindet. Anschließend navigieren wir zu 'Common /' und importieren das Modul 'Common'.

Dave
quelle
2
Ändern Sie den Pfad des Python-Moduls nicht manuell, möglicherweise nur für schnelle Hacks. Das Erlernen der Python-Paketverwaltung mit Distutils, Setuptools usw. ist normalerweise eine erforderliche Fähigkeit, um solche Probleme zu lösen.
Sascha Gottfried
1
@SaschaGottfried stimmt voll und ganz zu, obwohl es wahrscheinlich keine Rolle spielt, wenn Sie kein verteilbares Paket erstellen. In Django installieren Sie Ihre App beispielsweise nie wirklich mit Distutils. Die oben beschriebene Methode ist also ein einfacher Hack. Aber trotzdem habe ich die Antwort so bearbeitet, wie ich es heutzutage tun würde.
Dave
32
Vielen Dank für die Beantwortung der eigentlichen Frage, anstatt über die richtige Technik zu predigen. Es gibt viele gute Gründe für relative Importe.
Spitzmaus
Wie würden Sie mehr als eine Ebene aufsteigen?
Jxramos
10
Um eine weitere Ebene zu erreichen, verwenden Sie für jede Ebene einen zusätzlichen Punkt. @ jxramos ex: from ...myfilegeht zu../../myfile
WattsInABox
9

Komisch genug, ein Problem, das ich gerade getroffen habe, und ich bekomme diese Arbeit auf folgende Weise:

In Kombination mit dem Linux-Befehl lnkönnen wir die Sache viel einfacher machen:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

Und jetzt, wenn Sie some_stuffaus Datei importieren möchten : Proj/Common/Common.pyin Ihre Datei : Proj/Client/Client.py, einfach so:

# in Proj/Client/Client.py
from Common.Common import some_stuff

Und das gleiche gilt für Proj/Server, funktioniert auch für den setup.pyProzess, eine gleiche Frage hier diskutiert , hoffe es hilft!

jacoolee
quelle
9

Führen Sie keinen relativen Import durch.

Aus PEP8 :

Von relativen Importen für Intra-Package-Importe wird dringend abgeraten.

Fügen Sie Ihren gesamten Code in ein Superpaket (dh "myapp") ein und verwenden Sie Unterpakete für Client, Server und allgemeinen Code.

Update: " Python 2.6 und 3.x unterstützen ordnungsgemäße relative Importe (...) ". Weitere Informationen finden Sie in Daves Antworten .

Michał Šrajer
quelle
1
Stellen Sie sich vor, Sie fügen nach der if __name__ == "__main__":Zeile ' ' am Ende von Client und Server Code hinzu. Das heißt, Sie möchten sie als eigenständige Skripte verwenden können. Wie mache ich das richtig? Ich denke, es ist ein durchaus üblicher Anwendungsfall, der unterstützt werden sollte. Warum wird davon abgeraten?
Jabba
82
Ich bin überrascht, dass "Don't do it" die akzeptierte Antwort auf eine "how do I ..." - Frage ist (außer bei Rails <g>). Es gibt gelegentlich Gründe, dies zu tun. Ich verwende eine ähnliche Lösung wie Dave vorschlägt.
Tom Wilson
1
@ TomWilson: Es ist keine reine "Tu es nicht" Antwort. Es gibt unten "mach es so".
Michał Šrajer
2
Jemand sollte es den Jungs bei Numpy erzählen! Sie verwenden eine TONNE relativer Importe!
Austin A
12
Diese Antwort gilt nicht für aktuelle Versionen von Python. Der zitierte Teil ist in PEP 8 nicht mehr zu finden. Heutzutage lautet er wie folgt: "Explizite relative Importe sind eine akzeptable Alternative zu absoluten Importen, insbesondere bei komplexen Paketlayouts, bei denen die Verwendung absoluter Importe unnötig ausführlich wäre"
moooeeeep
8

Ein relativer Import ist absolut in Ordnung! Hier ist, was das kleine Ich tut:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py
Gary Beardsley
quelle
1
Aber Sie sollten besser wissen, wohin sys.argv [0] tatsächlich zeigt - es ist (wahrscheinlich) nicht das Verzeichnis, in dem Sie sich befanden, als Sie Python gestartet haben.
CarlH
Dies ist ein schneller Hack mit vielen Fallstricken. Aber die Frage war nicht noch besser.
Sascha Gottfried
1
Dies ist klar geschrieben, aber der ursprüngliche Hack in Daves Antwort ist besser, weil er verwendet wird __file__, um die richtige Beziehung aus der aktuellen Datei zu erhalten
John Neuhaus
4

Die Standardimportmethode aus dem PYTHONPATH ist bereits "relativ". Der PYTHONPATH wird standardmäßig für einige Systembibliotheken zusammen mit dem Ordner der ursprünglichen Quelldatei verwendet. Wenn Sie mit -m ausführen, um ein Modul auszuführen, wird das aktuelle Verzeichnis zum PYTHONPATH hinzugefügt. Wenn sich der Einstiegspunkt Ihres Programms in Proj befindet, import Common.Commonsollte die Verwendung sowohl in Server.py als auch in Client.py funktionieren.

Führen Sie keinen relativen Import durch. Es wird nicht so funktionieren, wie Sie es wollen.

Jonathan Sternberg
quelle
1
Wenn dies wahr ist, warum sagen die Top-Antworten dies nicht? Wird das funktionieren oder nicht?
Anonym