Skript vs. Modul
Hier ist eine Erklärung. Die Kurzversion ist, dass es einen großen Unterschied zwischen dem direkten Ausführen einer Python-Datei und dem Importieren dieser Datei von einem anderen Ort gibt. Nur zu wissen, in welchem Verzeichnis sich eine Datei befindet, bestimmt nicht, in welchem Paket Python sich befindet. Dies hängt außerdem davon ab, wie Sie die Datei in Python laden (durch Ausführen oder Importieren).
Es gibt zwei Möglichkeiten, eine Python-Datei zu laden: als Skript der obersten Ebene oder als Modul. Eine Datei wird als Skript der obersten Ebene geladen, wenn Sie sie direkt ausführen, z. B. durch Eingabe python myfile.py
in der Befehlszeile. Es wird als Modul geladen, wenn Sie dies tun python -m myfile
, oder wenn es geladen wird, wenn eine import
Anweisung in einer anderen Datei gefunden wird. Es kann immer nur ein Skript der obersten Ebene vorhanden sein. Das Skript der obersten Ebene ist die Python-Datei, die Sie ausgeführt haben, um die Dinge zu starten.
Benennung
Wenn eine Datei geladen wird, erhält sie einen Namen (der in ihrem __name__
Attribut gespeichert ist ). Wenn es als Skript der obersten Ebene geladen wurde, lautet sein Name __main__
. Wenn es als Modul geladen wurde, ist sein Name der Dateiname, vor dem die Namen aller Pakete / Unterpakete stehen, zu denen es gehört, getrennt durch Punkte.
Also zum Beispiel in Ihrem Beispiel:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
Wenn Sie importiert haben moduleX
(Hinweis: importiert , nicht direkt ausgeführt), lautet der Name package.subpackage1.moduleX
. Wenn Sie importieren moduleA
, wäre der Name package.moduleA
. Wenn Sie jedoch direkt moduleX
über die Befehlszeile ausgeführt werden, lautet der Name stattdessen __main__
, und wenn Sie direkt moduleA
über die Befehlszeile ausgeführt werden, lautet der Name __main__
. Wenn ein Modul als Skript der obersten Ebene ausgeführt wird, verliert es seinen normalen Namen und stattdessen seinen Namen __main__
.
Zugriff auf ein Modul NICHT über das enthaltene Paket
Es gibt eine zusätzliche Falte: Der Name des Moduls hängt davon ab, ob es "direkt" aus dem Verzeichnis, in dem es sich befindet, oder über ein Paket importiert wurde. Dies macht nur dann einen Unterschied, wenn Sie Python in einem Verzeichnis ausführen und versuchen, eine Datei in dasselbe Verzeichnis (oder ein Unterverzeichnis davon) zu importieren. Wenn Sie beispielsweise den Python-Interpreter im Verzeichnis starten package/subpackage1
und dies dann tun import moduleX
, lautet der Name moduleX
nur moduleX
und nicht package.subpackage1.moduleX
. Dies liegt daran, dass Python beim Start das aktuelle Verzeichnis zu seinem Suchpfad hinzufügt. Wenn das zu importierende Modul im aktuellen Verzeichnis gefunden wird, weiß es nicht, dass dieses Verzeichnis Teil eines Pakets ist, und die Paketinformationen werden nicht Teil des Modulnamens.
Ein Sonderfall ist, wenn Sie den Interpreter interaktiv ausführen (z. B. einfach python
Python-Code eingeben und sofort eingeben). In diesem Fall lautet der Name dieser interaktiven Sitzung __main__
.
Hier ist das Entscheidende für Ihre Fehlermeldung: Wenn der Name eines Moduls keine Punkte enthält, wird er nicht als Teil eines Pakets betrachtet . Es spielt keine Rolle, wo sich die Datei tatsächlich auf der Festplatte befindet. Alles, was zählt, ist der Name und der Name hängt davon ab, wie Sie ihn geladen haben.
Schauen Sie sich nun das Zitat an, das Sie in Ihre Frage aufgenommen haben:
Relative Importe verwenden das Namensattribut eines Moduls, um die Position dieses Moduls in der Pakethierarchie zu bestimmen. Wenn der Name des Moduls keine Paketinformationen enthält (z. B. auf 'main' gesetzt), werden relative Importe so aufgelöst, als wäre das Modul ein Modul der obersten Ebene, unabhängig davon, wo sich das Modul tatsächlich im Dateisystem befindet.
Relative Importe ...
Relative Importe verwenden den Namen des Moduls, um zu bestimmen, wo es sich in einem Paket befindet. Wenn Sie einen relativen Import wie verwenden from .. import foo
, geben die Punkte an, dass einige Ebenen in der Pakethierarchie erhöht werden sollen. Wenn der Name Ihres aktuellen Moduls beispielsweise lautet package.subpackage1.moduleX
, ..moduleA
würde dies bedeuten package.moduleA
. Damit ein from .. import
Modul funktioniert, muss der Name des Moduls mindestens so viele Punkte enthalten, wie in der import
Anweisung enthalten sind.
... sind nur in einem Paket relativ
Wenn der Name Ihres Moduls jedoch lautet __main__
, wird er nicht als in einem Paket enthalten betrachtet. Sein Name hat keine Punkte und daher können Sie keine darin enthaltenen from .. import
Anweisungen verwenden. Wenn Sie dies versuchen, wird der Fehler "Relativer Import in Nicht-Paket" angezeigt.
Skripte können nicht relativ importiert werden
Was Sie wahrscheinlich getan haben, ist, dass Sie versucht haben, moduleX
über die Befehlszeile oder ähnliches auszuführen . Als Sie dies getan haben, wurde sein Name auf gesetzt __main__
, was bedeutet, dass relative Importe darin fehlschlagen, da sein Name nicht anzeigt, dass es sich in einem Paket befindet. Beachten Sie, dass dies auch passiert, wenn Sie Python aus demselben Verzeichnis ausführen, in dem sich ein Modul befindet, und dann versuchen, dieses Modul zu importieren, da Python das Modul wie oben beschrieben "zu früh" im aktuellen Verzeichnis findet, ohne es zu bemerken Teil eines Pakets.
Denken Sie auch daran, dass beim Ausführen des interaktiven Interpreters immer der "Name" dieser interaktiven Sitzung lautet __main__
. Daher können Sie keine relativen Importe direkt aus einer interaktiven Sitzung durchführen . Relative Importe sind nur zur Verwendung in Moduldateien vorgesehen.
Zwei Lösungen:
Wenn Sie wirklich moduleX
direkt ausgeführt werden möchten, es aber dennoch als Teil eines Pakets betrachtet werden sollen, können Sie dies tun python -m package.subpackage1.moduleX
. Das -m
weist Python an, es als Modul zu laden, nicht als Skript der obersten Ebene.
Oder vielleicht möchten Sie nicht wirklich ausführen moduleX
, sondern nur ein anderes Skript ausführen myfile.py
, das beispielsweise Funktionen verwendetmoduleX
. Wenn dies der Fall ist, legen Sie es an einer myfile.py
anderen Stelle ab - nicht im package
Verzeichnis - und führen Sie es aus. Wenn myfile.py
Sie Dinge wie tun from package.moduleA import spam
, wird es gut funktionieren.
Anmerkungen
Für jede dieser Lösungen muss auf das Paketverzeichnis ( package
in Ihrem Beispiel) über den Suchpfad des Python-Moduls ( sys.path
) zugegriffen werden können . Ist dies nicht der Fall, können Sie nichts im Paket zuverlässig verwenden.
Seit Python 2.6 wird der "Name" des Moduls für Zwecke der Paketauflösung nicht nur durch seine __name__
Attribute, sondern auch durch das __package__
Attribut bestimmt. Deshalb vermeide ich es, das explizite Symbol __name__
zu verwenden, um auf den "Namen" des Moduls zu verweisen. Da Python 2.6 ein Modul der „name“ ist effektiv __package__ + '.' + __name__
, oder einfach nur , __name__
wenn __package__
ist None
.)