5. Das Importsystem
*******************

Python-Code in einem *Modul* erhält Zugriff auf den Code in einem
anderen Modul, indem er diesen *importiert*. Die Anweisung "import"
ist die gängigste Methode, um den Importvorgang auszulösen, aber es
ist nicht die einzige Möglichkeit. Auch Funktionen wie `
"importlib.import_module()" und die integrierte Funktion
"__import__()" können verwendet werden, um den Importvorgang
auszulösen.

Die Anweisung "import" kombiniert zwei Operationen: Sie sucht nach dem
genannten Modul und bindet anschließend die Ergebnisse dieser Suche an
einen Namen im lokalen Geltungsbereich. Die Suchoperation der
Anweisung „ "import" ist als Aufruf der Funktion "__import__()" mit
den entsprechenden Argumenten definiert. Der Rückgabewert von
"__import__()" wird verwendet, um die Namensbindung der Anweisung
"import" durchzuführen.  Genaue Einzelheiten zu dieser Namensbindung
finden Sie in der Anweisung "import" .

Ein direkter Aufruf von "__import__()" führt lediglich die Modulsuche
durch und, falls das Modul gefunden wird, die Modulerstellung. Zwar
können dabei gewisse Nebeneffekte auftreten, wie beispielsweise das
Importieren übergeordneter Pakete und die Aktualisierung verschiedener
Caches (einschließlich "sys.modules"), doch nur die Anweisung "import"
führt eine Namensbindung durch.

Bei der Ausführung einer Anweisung vom Typ "import" wird die
standardmäßige integrierte Funktion "__import__()" aufgerufen. Andere
Mechanismen zum Aufruf des Importsystems (wie beispielsweise
"importlib.import_module()" ) können "__import__()" umgehen und
stattdessen eigene Lösungen zur Implementierung der Import-Semantik
verwenden.

Wenn ein Modul zum ersten Mal importiert wird, sucht Python nach dem
Modul und erstellt, falls es gefunden wird, ein Modulobjekt [1] und
initialisiert es.  Kann das genannte Modul nicht gefunden werden, wird
eine Ausnahme vom Typ "ModuleNotFoundError" ausgelöst.  Python setzt
verschiedene Strategien ein, um nach dem genannten Modul zu suchen,
wenn der Importmechanismus aufgerufen wird. Diese Strategien können
mithilfe verschiedener Hooks, die in den folgenden Abschnitten
beschrieben werden, angepasst und erweitert werden.

Geändert in Version 3.3: Das Import-System wurde aktualisiert, um die
zweite Phase von **PEP 302** vollständig umzusetzen. Es gibt keine
implizite Import-Mechanik mehr – das gesamte Import-System wird über
"sys.meta_path" bereitgestellt. Darüber hinaus wurde die native
Unterstützung für Namespace-Pakete implementiert (siehe **PEP 420**).


5.1. "importlib"
================

Das Modul "importlib" bietet eine umfangreiche API für die Interaktion
mit dem Import-System. So stellt beispielsweise
"importlib.import_module()" eine empfohlene, einfachere API zum
Aufrufen der Import-Funktionen dar als die integrierte Funktion
"__import__()" “. Weitere Informationen finden Sie in der
Dokumentation zur Bibliothek "importlib" .


5.2. Pakete
===========

Python kennt nur einen Typ von Modulobjekt, und alle Module gehören zu
diesem Typ, unabhängig davon, ob das Modul in Python, C oder einer
anderen Sprache implementiert ist. Um die Organisation von Modulen zu
erleichtern und eine Namenshierarchie bereitzustellen, gibt es in
Python das Konzept der *Pakete*.

Man kann sich Pakete wie Verzeichnisse in einem Dateisystem und Module
wie Dateien innerhalb dieser Verzeichnisse vorstellen, sollte diese
Analogie jedoch nicht allzu wörtlich nehmen, da Pakete und Module
nicht unbedingt aus dem Dateisystem stammen müssen.  Für die Zwecke
dieser Dokumentation werden wir diese praktische Analogie von
Verzeichnissen und Dateien verwenden.  Wie Verzeichnisse im
Dateisystem sind Pakete hierarchisch organisiert, und Pakete können
ihrerseits sowohl Unterpakete als auch reguläre Module enthalten.

Man sollte unbedingt beachten, dass alle Pakete Module sind, aber
nicht alle Module Pakete sind. Oder anders ausgedrückt: Pakete sind
lediglich eine besondere Art von Modulen. Genauer gesagt gilt jedes
Modul, das ein Attribut "__path__" enthält, als Paket.

Alle Module haben einen Namen. Die Namen von Unterpaketen werden durch
einen Punkt vom Namen ihres übergeordneten Pakets getrennt, ähnlich
wie bei der Standard-Syntax für den Zugriff auf Attribute in Python.
So könnte es beispielsweise ein Paket namens "email" geben, das
wiederum ein Unterpaket namens "email.mime" enthält, in dem sich ein
Modul namens "email.mime.text" befindet.


5.2.1. Reguläre Pakete
----------------------

Python definiert zwei Arten von Paketen: *reguläre Pakete* und
*Namespace-Pakete*. Reguläre Pakete sind herkömmliche Pakete, wie sie
bereits in Python 3.2 und früheren Versionen existierten. Ein
reguläres Paket wird in der Regel als Verzeichnis implementiert, das
eine Datei "__init__.py" enthält.  Wenn ein reguläres Paket importiert
wird, wird diese Datei "__init__.py" implizit ausgeführt, und die
darin definierten Objekte werden an Namen im Namensraum des Pakets
gebunden. Die Datei "__init__.py" kann denselben Python-Code enthalten
wie jedes andere Modul auch, und Python fügt dem Modul beim
Importieren einige zusätzliche Attribute hinzu.

Beispielsweise definiert die folgende Dateisystemstruktur ein Paket
der obersten Ebene "parent" mit drei Unterpaketen:

   parent/
       __init__.py
       one/
           __init__.py
       two/
           __init__.py
       three/
           __init__.py

Durch das Importieren von "parent.one" werden implizit die Dateien
"parent/__init__.py" und "parent/one/__init__.py" ausgeführt. Bei
nachfolgenden Importen von "parent.two" oder "parent.three" werden
jeweils die Dateien "parent/two/__init__.py" und
"parent/three/__init__.py" ausgeführt.

Ein Unterverzeichnis innerhalb eines regulären Pakets, das keine Datei
"__init__.py" enthält, wird als implizites namespace-Paket (ein
"Namespace-Unterpaket") behandelt, dessen Stammverzeichnis das
übergeordnete Paket ist. Die zugrunde liegende Spezifikation finden
Sie unter **PEP 420**.


5.2.2. Namespace-Pakete
-----------------------

Ein Namespace-Paket ist eine Zusammensetzung aus verschiedenen
*Teilen*, wobei jeder Teil ein Unterpaket zum übergeordneten Paket
beiträgt. Teile können sich an verschiedenen Orten im Dateisystem
befinden. Teile können sich auch in ZIP-Dateien, im Netzwerk oder an
jedem anderen Ort befinden, den Python beim Import durchsucht.
Namespace-Pakete müssen nicht unbedingt direkt mit Objekten im
Dateisystem korrespondieren; es kann sich um virtuelle Module handeln,
die keine konkrete Darstellung haben.

Namespace-Pakete verwenden für ihr Attribut "__path__" keine
gewöhnliche Liste. Stattdessen nutzen sie einen benutzerdefinierten
iterierbaren Typ, der beim nächsten Importversuch innerhalb dieses
Pakets automatisch eine neue Suche nach Paketteilen durchführt, falls
sich der Pfad ihres übergeordneten Pakets (oder "sys.path" bei einem
Paket der obersten Ebene) ändert.

Bei Namespace-Paketen gibt es keine Datei "parent/__init__.py" .
Tatsächlich können bei der Importsuche mehrere Verzeichnisse "parent"
gefunden werden, wobei jedes von einem anderen Teil bereitgestellt
wird. Daher befindet sich "parent/one" möglicherweise nicht physisch
neben „ "parent/two" . In diesem Fall erstellt Python ein Namespace-
Paket für das Paket "parent" auf oberster Ebene, sobald dieses oder
eines seiner Unterpakete importiert wird.

Namespace-Pakete können auch innerhalb eines regulären Pakets
verschachtelt sein. Wenn das Import-System die Datei "__path__" eines
regulären Pakets durchsucht und auf ein Unterverzeichnis stößt, das
keine "__init__.py" -Datei enthält, wird dieses Unterverzeichnis zu
einem *Teil*, der zu einem Namespace-Unterpaket des umgebenden
regulären Pakets beiträgt.

Siehe auch **PEP 420** für die Spezifikation des Namespace-Pakets.


5.3. Suchen
===========

Um die Suche zu starten, benötigt Python den *vollständig
qualifizierten* Namen des Moduls (oder Pakets; für die Zwecke dieser
Erörterung ist der Unterschied jedoch unerheblich), das importiert
werden soll. Dieser Name kann aus verschiedenen Argumenten der
Anweisung "import" oder aus den Parametern der Funktionen
"importlib.import_module()" oder "__import__()" stammen.

Dieser Name wird in verschiedenen Phasen der Import-Suche verwendet
und kann den durch Punkte getrennten Pfad zu einem Submodul
darstellen, z. B. "foo.bar.baz". In diesem Fall versucht Python
zunächst, "foo" zu importieren, dann "foo.bar" und schließlich
"foo.bar.baz". Wenn einer der Zwischenimporte fehlschlägt, wird ein
"ModuleNotFoundError" ausgelöst.


5.3.1. Der Modul-Cache
----------------------

Bei der Suche nach importierten Modulen wird zunächst unter
"sys.modules" nachgeschaut. Diese Zuordnung dient als Cache für alle
Module, die zuvor importiert wurden, einschließlich der Zwischenpfade.
Wenn also "foo.bar.baz" zuvor importiert wurde, enthält "sys.modules"
Einträge für "foo", "foo.bar" und "foo.bar.baz". Jeder Schlüssel hat
als Wert das entsprechende Modulobjekt.

Beim Import wird der Modulname unter "sys.modules" nachgeschlagen. Ist
dort ein Eintrag vorhanden, entspricht der zugehörige Wert dem Modul,
das den Import erfüllt, und der Vorgang wird abgeschlossen. Ist der
Wert jedoch "None", wird eine Ausnahme vom Typ "ModuleNotFoundError"
ausgelöst. Fehlt der Modulname, setzt Python die Suche nach dem Modul
fort.

"sys.modules" ist beschreibbar. Das Löschen eines Schlüssels führt
möglicherweise nicht zur Löschung des zugehörigen Moduls (da andere
Module möglicherweise Verweise darauf enthalten), macht jedoch den
Cache-Eintrag für das genannte Modul ungültig, sodass Python bei
dessen nächstem Import erneut nach dem genannten Modul sucht. Dem
Schlüssel kann auch der Wert "None" zugewiesen werden, wodurch der
nächste Import des Moduls zwangsläufig zu einem "ModuleNotFoundError"
führt.

Beachten Sie jedoch: Wenn Sie einen Verweis auf das Modulobjekt
beibehalten, dessen Cache-Eintrag unter "sys.modules" ungültig machen
und anschließend das genannte Modul erneut importieren, sind die
beiden Modulobjekte *nicht* identisch. Im Gegensatz dazu wird bei
"importlib.reload()" das *gleiche* Modulobjekt wiederverwendet und der
Inhalt des Moduls durch erneutes Ausführen des Modulcodes einfach neu
initialisiert.


5.3.2. Finders und Loader
-------------------------

Wird das angegebene Modul nicht unter "sys.modules" gefunden, wird das
Importprotokoll von Python aufgerufen, um das Modul zu suchen und zu
laden. Dieses Protokoll besteht aus zwei konzeptionellen Objekten:
*finders* und *loaders*. Die Aufgabe eines Finders besteht darin,
mithilfe aller ihm bekannten Strategien festzustellen, ob er das
angegebene Modul finden kann. Objekte, die beide dieser Schnittstellen
implementieren, werden als *Importer* bezeichnet – sie geben sich
selbst zurück, wenn sie feststellen, dass sie das angeforderte Modul
laden können.

Python enthält eine Reihe von Standard-Findern und -Importern. Der
erste findet eingebaute Module, der zweite findet „frozen“ Module.
Ein dritter Standard-Finder durchsucht einen *Importpfad* nach
Modulen. Der *Importpfad* ist eine Liste von Speicherorten, die
Dateisystempfade oder ZIP-Dateien bezeichnen können. Er lässt sich
auch erweitern, um nach beliebigen auffindbaren Ressourcen zu suchen,
beispielsweise solchen, die durch URLs identifiziert werden.

Die Importmechanismen sind erweiterbar, sodass neue Suchfunktionen
hinzugefügt werden können, um den Umfang und die Reichweite der
Modulsuche zu erweitern.

Finder laden Module nicht tatsächlich. Wenn sie das angegebene Modul
finden können, geben sie eine *Modulspezifikation* zurück, eine
Kapselung der importbezogenen Informationen des Moduls, die der
Importmechanismus dann beim Laden des Moduls verwendet.

In den folgenden Abschnitten wird das Protokoll für Finder und Loader
näher beschrieben, einschließlich der Vorgehensweise, wie Sie neue
Finder und Loader erstellen und registrieren können, um die
Importmechanismen zu erweitern.

Geändert in Version 3.4: In früheren Python-Versionen gaben
Suchfunktionen direkt *Loader* zurück, während sie nun
Modulspezifikationen zurückgeben, die Loader *enthalten*. Loader
werden beim Import weiterhin verwendet, haben jedoch weniger Aufgaben.


5.3.3. Import-Hooks
-------------------

Die Import-Mechanismen sind so konzipiert, dass sie erweiterbar sind;
der wichtigste Mechanismus hierfür sind die *Import-Hooks*. Es gibt
zwei Arten von Import-Hooks: *Meta-Hooks* und *Import-Pfad-Hooks*.

Meta-Hooks werden zu Beginn der Importverarbeitung aufgerufen, noch
bevor andere Importvorgänge stattfinden – mit Ausnahme der Cache-
Abfrage unter "sys.modules" “. Dadurch können Meta-Hooks die
Verarbeitung von "sys.path", eingefrorene Module oder sogar
integrierte Module überschreiben. Meta-Hooks werden registriert, indem
neue Finder-Objekte zu „ "sys.meta_path" hinzugefügt werden, wie im
Folgenden beschrieben.

Import-Pfad-Hooks werden im Rahmen der Verarbeitung von "sys.path"
(oder "package.__path__" ) an der Stelle aufgerufen, an der das
zugehörige Pfadelement gefunden wird. Import-Pfad-Hooks werden
registriert, indem neue aufrufbare Funktionen wie unten beschrieben zu
"sys.path_hooks" hinzugefügt werden.


5.3.4. Der Metapfad
-------------------

Wenn das genannte Modul unter "sys.modules" nicht gefunden wird,
durchsucht Python als Nächstes "sys.meta_path", das eine Liste von
Meta-Path-Finder-Objekten enthält. Diese Finder werden abgefragt, um
festzustellen, ob sie wissen, wie das genannte Modul zu behandeln ist.
Meta-Pfadfinder müssen eine Methode namens "find_spec()"
implementieren, die drei Argumente entgegennimmt: einen Namen, einen
Importpfad und (optional) ein Zielmodul. Der Meta-Pfadfinder kann eine
beliebige Strategie anwenden, um festzustellen, ob er das genannte
Modul verarbeiten kann oder nicht.

Wenn der Meta-Path-Finder weiß, wie das benannte Modul zu verarbeiten
ist, gibt er ein Spec-Objekt zurück. Kann er das benannte Modul nicht
verarbeiten, gibt er "None" zurück. Erreicht die Verarbeitung von
"sys.meta_path" das Ende der Liste, ohne ein Spec zurückzugeben, wird
eine "ModuleNotFoundError" -Ausnahme ausgelöst. Alle anderen
ausgelösten Ausnahmen werden einfach nach oben weitergeleitet, wodurch
der Importvorgang abgebrochen wird.

Die Methode "find_spec()" von Meta-Pfadfindern wird mit zwei oder drei
Argumenten aufgerufen. Das erste Argument ist der vollqualifizierte
Name des zu importierenden Moduls, zum Beispiel "foo.bar.baz". Das
zweite Argument enthält die Pfadeinträge, die für die Modulsuche
verwendet werden sollen.  Bei Modulen der obersten Ebene ist das
zweite Argument "None", bei Submodulen oder Subpaketen hingegen ist
das zweite Argument der Wert des Attributs "__path__" des
übergeordneten Pakets. Kann nicht auf das entsprechende Attribut
"__path__" zugegriffen werden, wird eine "ModuleNotFoundError"
ausgelöst. Das dritte Argument ist ein vorhandenes Modulobjekt, das
später als Ziel für das Laden dient. Das Import-System übergibt ein
Zielmodul nur während des Neuladens.

Der Metapfad kann bei einer einzelnen Importanforderung mehrfach
durchlaufen werden. Angenommen, keines der beteiligten Module wurde
bereits zwischengespeichert, dann führt der Import von "foo.bar.baz"
zunächst einen Import auf oberster Ebene durch, wobei bei jedem
Metapfad-Finder ("mpf") die Funktion "mpf.find_spec("foo", None,
None)" aufgerufen wird. Nachdem "foo" importiert wurde, wird "foo.bar"
durch ein zweites Durchlaufen des Metapfads importiert, wobei
"mpf.find_spec("foo.bar", foo.__path__, None)" aufgerufen wird. Sobald
"foo.bar" importiert wurde, ruft der letzte Durchlauf
"mpf.find_spec("foo.bar.baz", foo.bar.__path__, None)" auf.

Einige Meta-Path-Finder unterstützen nur Importe auf oberster Ebene.
Diese Importer geben stets "None" zurück, wenn als zweites Argument
etwas anderes als "None" übergeben wird.

Pythons Standard- "sys.meta_path" verfügt über drei Meta-Pfadfinder:
einen, der weiß, wie man integrierte Module importiert, einen, der
weiß, wie man "frozen" Module importiert, und einen, der weiß, wie man
Module aus einem *Importpfad* importiert (d. h. den *pfadbasierten
Finder*).

Geändert in Version 3.4: Die Methode "find_spec()" der Meta-Path-
Finder hat "find_module()" ersetzt, die nun veraltet ist. Sie
funktioniert zwar weiterhin unverändert, doch der Importmechanismus
greift nur dann darauf zurück, wenn der Finder "find_spec()" nicht
implementiert.

Geändert in Version 3.10: Die Verwendung von "find_module()" durch das
Import-System löst nun den Fehler "ImportWarning" aus.

Geändert in Version 3.12: "find_module()" wurde entfernt. Verwenden
Sie stattdessen "find_spec()".


5.4. Module laden
=================

Wird eine Modulspezifikation gefunden, verwendet der Importmechanismus
diese (und den darin enthaltenen Loader) beim Laden des Moduls. Hier
ist eine grobe Beschreibung dessen, was während des Ladevorgangs von
"import:" geschieht:

   module = None
   if spec.loader is not None and hasattr(spec.loader, 'create_module'):
       # Es wird davon ausgegangen, dass "exec_module" ebenfalls auf dem Loader definiert ist..
       module = spec.loader.create_module(spec)
   if module is None:
       module = ModuleType(spec.name)
   # Die importbezogenen Modulattribute werden hier gesetzt.:
   _init_module_attrs(spec, module)

   if spec.loader is None:
       # nicht unterstützt
       raise ImportError
   if spec.origin is None and spec.submodule_search_locations is not None:
       # Namensraumpaket
       sys.modules[spec.name] = module
   elif not hasattr(spec.loader, 'exec_module'):
       module = spec.loader.load_module(spec.name)
   else:
       sys.modules[spec.name] = module
       try:
           spec.loader.exec_module(module)
       except BaseException:
           try:
               del sys.modules[spec.name]
           except KeyError:
               pass
           raise
   return sys.modules[spec.name]

Beachte bitte folgende Details:

* Wenn unter "sys.modules" bereits ein Modulobjekt mit dem angegebenen
  Namen vorhanden ist, hat "import" dieses bereits zurückgegeben.

* Das Modul wird in "sys.modules" vorhanden sein, bevor der Loader den
  Modulcode ausführt. Dies ist von entscheidender Bedeutung, da der
  Modulcode sich möglicherweise (direkt oder indirekt) selbst
  importiert; durch das vorherige Hinzufügen zu "sys.modules" wird im
  schlimmsten Fall eine unbegrenzte Rekursion und im besten Fall ein
  mehrfaches Laden verhindert.

* Wenn das Laden fehlschlägt, wird das fehlerhafte Modul – und nur das
  fehlerhafte Modul – aus "sys.modules" entfernt. Alle Module, die
  sich bereits im Cache von "sys.modules" befinden, sowie alle Module,
  die als Nebeneffekt erfolgreich geladen wurden, müssen im Cache
  verbleiben. Dies steht im Gegensatz zum Neuladen, bei dem selbst das
  fehlerhafte Modul in "sys.modules" verbleibt.

* Nachdem das Modul erstellt wurde, aber noch vor seiner Ausführung,
  legt der Importmechanismus die importbezogenen Modulattribute fest
  ("_init_module_attrs" im obigen Pseudocode-Beispiel), wie in einem
  späteren Abschnitt zusammengefasst.

* Die Modulausführung ist der entscheidende Moment beim Laden, in dem
  der Namensraum des Moduls gefüllt wird. Die Ausführung wird
  vollständig an den Loader delegiert, der entscheidet, was wie
  gefüllt wird.

* Das beim Laden erstellte und an *exec_module()* übergebene Modul ist
  möglicherweise nicht dasselbe, das am Ende des Importvorgangs von
  [2] zurückgegeben wird.

Geändert in Version 3.4: Das Import-System hat die Routineaufgaben der
Loader übernommen. Diese wurden zuvor von der Methode
"importlib.abc.Loader.load_module()" ausgeführt.


5.4.1. Modullader
-----------------

Modullader erfüllen die entscheidende Funktion des Ladens: die
Ausführung des Moduls. Der Importmechanismus ruft die Methode
"importlib.abc.Loader.exec_module()" mit einem einzigen Argument auf,
nämlich dem auszuführenden Modulobjekt. Jeder von "exec_module()"
zurückgegebene Wert wird ignoriert.

Lader müssen die folgenden Anforderungen erfüllen:

* Handelt es sich bei dem Modul um ein Python-Modul (im Gegensatz zu
  einem integrierten Modul oder einer dynamisch geladenen
  Erweiterung), sollte der Loader den Code des Moduls im globalen
  Namensraum des Moduls ausführen ("module.__dict__").

* Wenn der Loader das Modul nicht ausführen kann, sollte er eine
  "ImportError" auslösen; alle anderen Ausnahmen, die während
  "exec_module()" ausgelöst werden, werden jedoch weitergegeben.

In vielen Fällen können Finder und Loader dasselbe Objekt sein; in
solchen Fällen würde die Methode "find_spec()"  lediglich eine
Spezifikation zurückgeben, bei der der Loader auf "self" gesetzt ist.

Modullader können sich dafür entscheiden, das Modulobjekt während des
Ladens zu erstellen, indem sie eine Methode "create_module()"
implementieren. Diese Methode nimmt ein Argument entgegen – die
Modulspezifikation – und gibt das neue Modulobjekt zurück, das während
des Ladens verwendet werden soll. "create_module()" muss keine
Attribute für das Modulobjekt festlegen. Wenn die Methode "None"
zurückgibt, erstellt der Importmechanismus das neue Modul selbst.

Added in version 3.4: Die "create_module()" -Methode bei Modullader.

Geändert in Version 3.4: Die Methode "load_module()" wurde durch
"exec_module()" ersetzt, und die Import-Mechanismen übernahmen alle
Routineaufgaben beim Laden.Um die Kompatibilität mit bestehenden
Ladern zu gewährleisten, verwendet die Import-Maschinerie die Methode
"load_module()" der Lader, sofern diese vorhanden ist und der Lader
nicht zusätzlich "exec_module()" implementiert. "load_module()" ist
jedoch veraltet, und Lader sollten stattdessen "exec_module()"
implementieren.Die Methode "load_module()" muss neben der Ausführung
des Moduls auch alle oben beschriebenen Standardfunktionen zum Laden
des Moduls implementieren. Es gelten dieselben Einschränkungen, wobei
einige zusätzliche Erläuterungen zu beachten sind:

* Wenn in "sys.modules" bereits ein Modulobjekt mit dem angegebenen
  Namen vorhanden ist, muss der Loader dieses vorhandene Modul
  verwenden. (Andernfalls funktioniert "importlib.reload()" nicht
  ordnungsgemäß.) Wenn das genannte Modul in "sys.modules" nicht
  vorhanden ist, muss der Loader ein neues Modulobjekt erstellen und
  es zu "sys.modules" hinzufügen.

* Das Modul *muss* in "sys.modules" vorhanden sein, bevor der Loader
  den Modulcode ausführt, um unbegrenzte Rekursion oder mehrfaches
  Laden zu verhindern.

* Sollte das Laden fehlschlagen, muss der Loader alle Module
  entfernen, die er in "sys.modules" eingefügt hat; dabei darf er
  jedoch **nur** die fehlerhaften Module entfernen, und zwar nur dann,
  wenn der Loader diese Module selbst explizit geladen hat.

Geändert in Version 3.5: Eine "DeprecationWarning" wird ausgelöst,
wenn "exec_module()" “ definiert ist, "create_module()" jedoch nicht.

Geändert in Version 3.6: Eine "ImportError" -Ausnahme wird ausgelöst,
wenn "exec_module()" definiert ist, "create_module()" jedoch nicht.

Geändert in Version 3.10: Die Verwendung von "load_module()" führt zu
"ImportWarning" .


5.4.2. Untermodule
------------------

Wenn ein Submodul über einen beliebigen Mechanismus geladen wird (z.
B. über die "importlib" -APIs, die Anweisungen "import" oder "import-
from" oder die integrierte Funktion "__import__()" ), wird im
Namensraum des übergeordneten Moduls eine Bindung zum Submodul-Objekt
hergestellt. Wenn beispielsweise das Paket "spam" ein Submodul "foo"
enthält, verfügt "spam" nach dem Import von "spam.foo"  über ein
Attribut "foo", das an das Submodul gebunden ist.  Nehmen wir an, Sie
haben die folgende Verzeichnisstruktur:

   spam/
       __init__.py
       foo.py

und die Datei "spam/__init__.py" enthält die folgende Zeile:

   from .foo import Foo

Wenn Sie anschließend den folgenden Befehl ausführen, werden im Modul
"spam" Namenszuordnungen für "foo" und "Foo" festgelegt:

   >>> import spam
   >>> spam.foo
   <module 'spam.foo' from '/tmp/imports/spam/foo.py'>
   >>> spam.Foo
   <class 'spam.foo.Foo'>

Angesichts der bekannten Regeln zur Namensbindung in Python mag dies
überraschend erscheinen, ist jedoch tatsächlich ein grundlegendes
Merkmal des Import-Systems. Die unveränderliche Regel lautet: Wenn Sie
"sys.modules['spam']" und "sys.modules['spam.foo']" haben (wie es nach
dem obigen Import der Fall wäre), muss Letzteres als Attribut "foo"
von Ersterem erscheinen.


5.4.3. Modulspezifikationen
---------------------------

Die Import-Maschinerie nutzt beim Import, insbesondere vor dem Laden,
eine Vielzahl von Informationen zu jedem Modul. Die meisten dieser
Informationen gelten für alle Module gleichermaßen. Der Zweck der
Spezifikation eines Moduls besteht darin, diese importbezogenen
Informationen modulweise zu kapseln.

Die Verwendung einer Spezifikation beim Import ermöglicht die
Übertragung des Zustands zwischen den Komponenten des Importsystems,
z. B. zwischen dem Finder, der die Modulspezifikation erstellt, und
dem Loader, der sie ausführt. Vor allem ermöglicht sie es dem
Importmechanismus, die Routinevorgänge des Ladens durchzuführen,
während ohne eine Modulspezifikation diese Aufgabe beim Loader lag.

Die Spezifikation des Moduls ist unter "module.__spec__" verfügbar.
Die entsprechende Einstellung von "__spec__" gilt gleichermaßen für
Module, die beim Start des Interpreters initialisiert werden. Die
einzige Ausnahme bildet "__main__", wo "__spec__" in einigen Fällen
auf None gesetzt wird.

Weitere Informationen zum Inhalt der Modulspezifikation finden Sie
unter "ModuleSpec".

Added in version 3.4.


5.4.4. __path__-Attribute in Modulen
------------------------------------

Das Attribut "__path__" sollte eine (möglicherweise leere) *Sequenz*
von Zeichenketten sein, die die Speicherorte auflistet, an denen die
Submodule des Pakets zu finden sind. Per Definition gilt: Wenn ein
Modul über ein Attribut "__path__" verfügt, handelt es sich um ein
*Paket*.

Das Attribut "__path__" eines Pakets wird beim Import seiner
Unterpakete verwendet. Innerhalb des Importmechanismus funktioniert es
ähnlich wie "sys.path", d. h., es liefert eine Liste von
Speicherorten, an denen beim Import nach Modulen gesucht wird.
Allerdings ist "__path__" in der Regel wesentlich stärker
eingeschränkt als  "sys.path" .

Die gleichen Regeln, die für "sys.path" gelten, gelten auch für die
"__path__" eines Pakets. "sys.path_hooks" (siehe unten) werden beim
Durchlaufen der "__path__" eines Pakets herangezogen.

Die Datei "__init__.py" eines Pakets kann das Attribut "__path__" des
Pakets festlegen oder ändern; auf diese Weise wurden Namespace-Pakete
vor der Einführung von **PEP 420** in der Regel implementiert. Mit der
Einführung von **PEP 420** müssen Namespace-Pakete keine "__init__.py"
“-Dateien mehr bereitstellen, die ausschließlich Code zur Bearbeitung
von "__path__" enthalten; die Import-Mechanik legt "__path__" für das
Namespace-Paket automatisch korrekt fest.


5.4.5. Modul-Repräsentanten
---------------------------

Standardmäßig verfügen alle Module über eine verwendbare "repr"
(Repräsentanten) Darstellung. Je nach den oben festgelegten Attributen
und den Angaben in der Modul-Spezifikation können Sie die
"repr"-Darstellung von Modulobjekten jedoch expliziter steuern.

Wenn das Modul über eine Spezifikation ("__spec__") verfügt, versucht
der Importmechanismus, daraus eine Repr zu generieren. Sollte dies
fehlschlagen oder keine Spezifikation vorhanden sein, erstellt das
Importsystem eine Standard-Repr unter Verwendung der für das Modul
verfügbaren Informationen. Dabei versucht es, die Dateien
"module.__name__", "module.__file__" und "module.__loader__" als
Eingabe für die Repr zu verwenden, wobei fehlende Informationen durch
Standardwerte ersetzt werden.

Hier sind die genauen Regeln, die angewendet wurden:

* Verfügt das Modul über ein Attribut "__spec__", werden die
  Informationen in der Spezifikation zur Generierung der Repr
  verwendet. Dabei werden die Attribute "name", "loader", "origin" und
  "has_location" herangezogen.

* Wenn das Modul über ein Attribut "__file__" verfügt, wird dieses als
  Teil der "repr"-Darstellung des Moduls verwendet.

* Wenn das Modul kein "__file__" hat, aber über ein "__loader__"
  verfügt, das nicht "None" ist, wird die *repr* des Laders als Teil
  der *repr* des Moduls verwendet.

* Ansonsten verwende einfach die Methode "__name__" des Moduls in der
  "repr"-Anweisung.

Geändert in Version 3.12: Die Verwendung von "module_repr()", die
bereits seit Python 3.4 als veraltet gilt, wurde in Python 3.12
entfernt und wird bei der Auflösung des *repr*-Objekts eines Moduls
nicht mehr aufgerufen.


5.4.6. Ungültigmachung von zwischengespeichertem Bytecode
---------------------------------------------------------

Bevor Python zwischengespeicherten Bytecode aus einer ".pyc" -Datei
lädt, prüft es, ob der Cache mit der Quelldatei ".py" auf dem neuesten
Stand ist. Standardmäßig speichert Python dazu beim Schreiben der
Cache-Datei den Zeitstempel der letzten Änderung sowie die Größe der
Quelldatei in der Cache-Datei. Zur Laufzeit überprüft das Import-
System dann die Cache-Datei, indem es die darin gespeicherten
Metadaten mit den Metadaten der Quell vergleicht.

Python unterstützt außerdem "hashbasierte" Cache-Dateien, die anstelle
der Metadaten einen Hash des Inhalts der Quelldatei speichern. Es gibt
zwei Varianten hashbasierter ".pyc" -Dateien: geprüfte und ungeprüfte.
Bei geprüften hashbasierten ".pyc" -Dateien überprüft Python die
Cache-Datei, indem es die Quelldatei hasht und den resultierenden Hash
mit dem Hash in der Cache-Datei vergleicht. Wird eine geprüfte hash-
basierte Cache-Datei als ungültig erkannt, generiert Python sie neu
und schreibt eine neue geprüfte hash-basierte Cache-Datei. Bei
ungeprüften hash-basierten ".pyc" -Dateien geht Python einfach davon
aus, dass die Cache-Datei gültig ist, sofern sie vorhanden ist. Das
Validierungsverhalten von hash-basierten ".pyc" -Dateien kann mit dem
Flag "--check-hash-based-pycs" überschrieben werden.

Geändert in Version 3.7: Es wurden Hash-basierte ".pyc" -Dateien
hinzugefügt. Bisher unterstützte Python nur die zeitstempelbasierte
Ungültigkeitserklärung von Bytecode-Caches.


5.5. Der pfadbasierte Finder
============================

Wie bereits erwähnt, verfügt Python über mehrere standardmäßige
Metapfad-Suchfunktionen. Eine davon, der sogenannte *pfadbasierte
Sucher* ("PathFinder"), durchsucht einen *Importpfad*, der eine Liste
von *Pfadeinträgen* enthält. Jeder Pfadeintrag gibt einen Speicherort
an, an dem nach Modulen gesucht werden soll.

Der pfadbasierte Finder selbst weiß nicht, wie man etwas importiert.
Stattdessen durchläuft er die einzelnen Pfadeinträge und ordnet jedem
von ihnen einen Pfadeintrags-Finder zu, der weiß, wie man mit dieser
bestimmten Art von Pfad umgeht.

Die standardmäßigen Pfadeintrags-Finder implementieren die gesamte
Semantik zum Auffinden von Modulen im Dateisystem und unterstützen
dabei spezielle Dateitypen wie Python-Quellcode (".py" -Dateien),
Python-Bytecode (".pyc" -Dateien) und gemeinsam genutzte Bibliotheken
(z. B. ".so" -Dateien). Sofern dies vom Modul "zipimport" in der
Standardbibliothek unterstützt wird, übernehmen die standardmäßigen
Pfadeintrags-Finder auch das Laden all dieser Dateitypen (mit Ausnahme
von gemeinsam genutzten Bibliotheken) aus ZIP-Dateien.

Pfadeinträge müssen sich nicht auf Speicherorte im Dateisystem
beschränken. Sie können sich auf URLs, Datenbankabfragen oder jeden
anderen Speicherort beziehen, der als Zeichenfolge angegeben werden
kann.

Der pfadbasierte Finder bietet zusätzliche Hooks und Protokolle, mit
denen du die Arten der durchsuchbaren Pfadeinträge erweitern und
anpassen können. Wenn du beispielsweise Pfadeinträge als Netzwerk-URLs
unterstützen möchtest, kannst du einen Hook schreiben, der HTTP-
Semantik implementiert, um Module im Internet zu finden.  Dieser Hook
(ein Callable) würde einen *Pfadeintrags-Finder* zurückgeben, der das
unten beschriebene Protokoll unterstützt, mit dem dann ein Loader für
das Modul aus dem Web abgerufen würde.

Eine Anmerkung: Sowohl in diesem Abschnitt als auch im vorherigen wird
der Begriff *Finder* verwendet, wobei durch die Begriffe *Meta-Pfad-
Finder* und *Pfad-Eintrag-Finder* zwischen ihnen unterschieden wird.
Diese beiden Arten von Findern sind sich sehr ähnlich, unterstützen
ähnliche Protokolle und funktionieren während des Importvorgangs auf
ähnliche Weise, doch es ist wichtig zu beachten, dass sie sich in
subtilen Punkten unterscheiden. Insbesondere werden Meta-Pfad-Finder
zu Beginn des Importvorgangs ausgeführt, ausgehend von der
Durchquerung des Verzeichnisses "sys.meta_path" .

Im Gegensatz dazu sind Pfad-Eintrag-Finder gewissermaßen ein
Implementierungsdetail des pfadbasierten Finders, und tatsächlich
würde, wenn der pfadbasierte Finder aus "sys.meta_path" entfernt
würde, keine der Semantiken der Pfadeintrags-Finder aufgerufen werden.


5.5.1. Pfadeintrag-Suchfunktionen
---------------------------------

Der *pfadbasierte Finder* ist dafür zuständig, Python-Module und
-Pakete zu finden und zu laden, deren Speicherort durch einen String
als *Pfadeintrag* angegeben wird. Die meisten Pfadeinträge bezeichnen
Speicherorte im Dateisystem, müssen sich jedoch nicht darauf
beschränken.

Als Meta-Pfadfinder implementiert der *pfadbasierte Finder* das zuvor
beschriebene Protokoll "find_spec()", stellt jedoch zusätzliche Hooks
bereit, mit denen sich die Art und Weise anpassen lässt, wie Module
über den *Importpfad* gefunden und geladen werden.

Der *path based finder* verwendet drei Variablen: "sys.path",
"sys.path_hooks" und "sys.path_importer_cache". Zudem werden die
Attribute "__path__" der Paketobjekte herangezogen. Diese bieten
zusätzliche Möglichkeiten zur Anpassung des Importmechanismus.

"sys.path" enthält eine Liste von Zeichenketten, die Suchpfade für
Module und Pakete angeben. Sie wird anhand der Umgebungsvariablen
"PYTHONPATH" sowie verschiedener anderer installations- und
implementierungsspezifischer Standardwerte initialisiert.  Einträge in
"sys.path" können Verzeichnisse im Dateisystem, ZIP-Dateien und
möglicherweise andere „Speicherorte“ (siehe das Modul "site")
benennen, an denen nach Modulen gesucht werden soll, wie z. B. URLs
oder Datenbankabfragen. In "sys.path" dürfen nur Zeichenketten
enthalten sein; alle anderen Datentypen werden ignoriert.

Der *pfadbasierte Finder* ist ein *Meta-Pfadfinder*, daher beginnt der
Importmechanismus die Suche nach dem *Importpfad*, indem er – wie
zuvor beschrieben – die Methode "find_spec()" des pfadbasierten
Finders aufruft.  Wenn das Argument "path" an "find_spec()" übergeben
wird, handelt es sich um eine Liste von String-Pfaden, die durchlaufen
werden sollen – typischerweise das Attribut "__path__" eines Pakets
für einen Import innerhalb dieses Pakets.  Wenn das Argument "path"
den Wert "None" hat, deutet dies auf einen Import auf oberster Ebene
hin, und es wird "sys.path" verwendet.

Der pfadbasierte Finder durchläuft jeden Eintrag im Suchpfad und sucht
für jeden dieser Einträge nach einem geeigneten *Pfadeintrags-Finder*
("PathEntryFinder") für den Pfadeintrag.  Da dies ein
ressourcenintensiver Vorgang sein kann (z. B. können bei dieser Suche
Overheads durch "stat()" “-Aufrufe entstehen), verwaltet der
pfadbasierte Finder einen Cache, der Pfadeinträge den Pfadeintrags-
Findern zuordnet.  Dieser Cache wird in "sys.path_importer_cache"
verwaltet (trotz des Namens speichert dieser Cache tatsächlich Finder-
Objekte und ist nicht auf *Importer*-Objekte beschränkt). Auf diese
Weise muss die aufwendige Suche nach dem *Pfadeintrags-Finder* für
einen bestimmten *Pfadeintrag* nur einmal durchgeführt werden.
Benutzercode kann Cache-Einträge aus "sys.path_importer_cache"
entfernen und so den pfadbasierten Finder dazu zwingen, die Suche nach
dem Pfadeintrag erneut durchzuführen.

Ist der Pfadeintrag nicht im Cache vorhanden, durchläuft der
pfadbasierte Finder alle aufrufbaren Funktionen in "sys.path_hooks".
Jeder der *Pfadeintrag-Hooks* in dieser Liste wird mit einem einzigen
Argument aufgerufen, nämlich dem zu durchsuchenden Pfadeintrag.  Diese
aufrufbare Funktion kann entweder einen *Pfadeintrags-Finder*
zurückgeben, der den Pfadeintrag verarbeiten kann, oder sie kann eine
"ImportError" auslösen.  Ein "ImportError" wird vom pfadbasierten
Finder verwendet, um zu signalisieren, dass der Hook keinen
*Pfadeintrags-Finder* für diesen *Pfadeintrag* finden kann.  Die
Ausnahme wird ignoriert und die Iteration über den *Importpfad* wird
fortgesetzt.  Der Hook sollte entweder eine Zeichenkette oder ein
Byte-Objekt erwarten; die Kodierung von Byte-Objekten bleibt dem Hook
überlassen (z. B. kann es sich um eine Dateisystemkodierung, UTF-8
oder etwas anderes handeln), und wenn der Hook das Argument nicht
dekodieren kann, sollte er eine "ImportError" -Ausnahme auslösen.

Wenn die Iteration von "sys.path_hooks" ohne Rückgabe eines
*Pfadeintrags-Finders* endet, speichert die Methode "find_spec()" des
pfadbasierten Finders "None" in "sys.path_importer_cache" (um
anzuzeigen, dass es keinen Finder für diesen Pfadeintrag gibt) und
gibt "None" zurück, was darauf hinweist, dass dieser *Meta-Pfad-
Finder* das Modul nicht finden konnte.

Wenn von einem der auf "sys.path_hooks" aufgeführten *path entry
hook*-Aufrufobjekte ein *path entry finder* *zurückgegeben* wird, wird
das folgende Protokoll verwendet, um vom Finder eine
Modulspezifikation abzufragen, die dann beim Laden des Moduls
verwendet wird.

The current working directory -- denoted by an empty string -- is
handled slightly differently from other entries on "sys.path". First,
if the current working directory is found to not exist, no value is
stored in "sys.path_importer_cache". Second, the value for the current
working directory is looked up fresh for each module lookup. Third,
the path used for "sys.path_importer_cache" and returned by
"importlib.machinery.PathFinder.find_spec()" will be the actual
current working directory and not the empty string.


5.5.2. Protokoll zur Ermittlung von Pfadeinträgen
-------------------------------------------------

Um das Importieren von Modulen und initialisierten Paketen zu
unterstützen und zudem Teile zu Namespace-Paketen beizusteuern, müssen
Pfadefinder die Methode "find_spec()" implementieren.

"find_spec()" nimmt zwei Argumente entgegen: den vollqualifizierten
Namen des zu importierenden Moduls und das (optionale) Zielmodul.
"find_spec()" gibt eine vollständig ausgefüllte Spezifikation für das
Modul zurück. In dieser Spezifikation ist "loader" immer gesetzt (mit
einer Ausnahme).

Um der Import-Maschinerie mitzuteilen, dass die Spezifikation einen
Namensraum *portion* darstellt, setzt der Pfadeintrags-Finder
"submodule_search_locations" auf eine Liste, die diesen Teil enthält.

Geändert in Version 3.4: "find_spec()" ersetzt "find_loader()" und
"find_module()", die beide mittlerweile veraltet sind, jedoch
verwendet werden, wenn "find_spec()" nicht definiert ist.Ältere
Pfadeintrags-Finder verwenden möglicherweise eine dieser beiden
veralteten Methoden anstelle von "find_spec()". Aus Gründen der
Abwärtskompatibilität werden diese Methoden weiterhin berücksichtigt.
Wenn jedoch "find_spec()" im Pfadeintrags-Finder implementiert ist,
werden die veralteten Methoden ignoriert."find_loader()" nimmt ein
Argument entgegen, nämlich den vollqualifizierten Namen des zu
importierenden Moduls.  "find_loader()" ` gibt ein 2-Tupel zurück,
dessen erstes Element der Loader und dessen zweites Element ein
Namespace-Teil *portion* ist.Aus Gründen der Abwärtskompatibilität mit
anderen Implementierungen des Importprotokolls unterstützen viele
Pfadeintrags-Finder ebenfalls dieselbe traditionelle Methode
"find_module()", die auch von Meta-Pfad-Findern unterstützt wird. Die
Methoden "find_module()" der Pfadeintrags-Finder werden jedoch niemals
mit einem Argument vom Typ "path" aufgerufen (es wird erwartet, dass
sie die entsprechenden Pfadinformationen aus dem ersten Aufruf des
Pfad-Hooks erfassen).Die Methode "find_module()" bei
Pfadeintragsfindern ist veraltet, da sie es dem Pfadeintragsfinder
nicht ermöglicht, Teile zu Namespace-Paketen beizusteuern. Wenn bei
einem Pfadeintragsfinder sowohl "find_loader()"  als auch
"find_module()" vorhanden sind, ruft das Import-System immer
"find_loader()" vorrangig vor "find_module()" auf.

Geändert in Version 3.10: Aufrufe von "find_module()" und
"find_loader()" durch das Importsystem lösen den Fehler
"ImportWarning" aus.

Geändert in Version 3.12: "find_module()" und "find_loader()" wurden
entfernt.


5.6. Ersetzen des Standard-Importsystems
========================================

Die zuverlässigste Methode, das gesamte Import-System zu ersetzen,
besteht darin, den Standardinhalt von "sys.meta_path" zu löschen und
ihn vollständig durch einen benutzerdefinierten Meta-Path-Hook zu
ersetzen.

Wenn es akzeptabel ist, lediglich das Verhalten von Importanweisungen
zu ändern, ohne andere APIs zu beeinträchtigen, die auf das
Importsystem zugreifen, könnte es ausreichen, die integrierte Funktion
"__import__()" zu ersetzen.

Um den Import bestimmter Module über einen Hook zu Beginn des Meta-
Pfads gezielt zu verhindern (anstatt das Standard-Import-System
vollständig zu deaktivieren), reicht es aus, direkt von "find_spec()"
aus eine "ModuleNotFoundError" -Ausnahme auszulösen, anstatt "None"
zurückzugeben. Letzteres signalisiert, dass die Suche im Meta-Pfad
fortgesetzt werden soll, während das Auslösen einer Ausnahme diese
sofort beendet.


5.7. Paketbezogene Importe
==========================

Relative Importe werden durch führende Punkte gekennzeichnet. Ein
einzelner führender Punkt kennzeichnet einen relativen Import, der vom
aktuellen Paket ausgeht. Zwei oder mehr führende Punkte kennzeichnen
einen relativen Import zu den übergeordneten Paketen des aktuellen
Pakets, wobei jeder Punkt nach dem ersten für eine Ebene steht.
Beispielsweise bei folgender Paketstruktur:

   package/
       __init__.py
       subpackage1/
           __init__.py
           moduleX.py
           moduleY.py
       subpackage2/
           __init__.py
           moduleZ.py
       moduleA.py

Sowohl in "subpackage1/moduleX.py" als auch in
"subpackage1/__init__.py" sind die folgenden relativen Importe gültig:

   from .moduleY import spam
   from .moduleY import spam as ham
   from . import moduleY
   from ..subpackage1 import moduleY
   from ..subpackage2.moduleZ import eggs
   from ..moduleA import foo

Absolute Importe können entweder die Syntax "import <>" oder "from <>
import <>" verwenden, relative Importe hingegen dürfen nur die zweite
Form verwenden; der Grund dafür ist, dass:

   import XXX.YYY.ZZZ

"XXX.YYY.ZZZ" sollte als gültiger Ausdruck verfügbar sein, aber
.moduleY ist kein gültiger Ausdruck.


5.8. Besondere Hinweise zu __main__
===================================

Das Modul "__main__" stellt im Zusammenhang mit dem Import-System von
Python einen Sonderfall dar.  Wie bereits an anderer Stelle erwähnt
:ref:` <programs>`, wird das Modul "__main__" direkt beim Start des
Interpreters initialisiert, ähnlich wie "sys" und "builtins". Im
Gegensatz zu diesen beiden Modulen gilt es jedoch nicht streng
genommen als integriertes Modul. Dies liegt daran, dass die Art und
Weise, wie "__main__" initialisiert wird, von den Flags und anderen
Optionen abhängt, mit denen der Interpreter aufgerufen wird.


5.8.1. __main__.__spec__
------------------------

Je nachdem, wie "__main__" initialisiert wird, wird
"__main__.__spec__" entsprechend gesetzt oder auf "None" .

Wenn Python mit der Option "-m" gestartet wird, wird "__spec__" auf
die Modul-Spezifikation des entsprechenden Moduls oder Pakets gesetzt.
"__spec__" wird ebenfalls gefüllt, wenn das Modul "__main__" im Rahmen
der Ausführung eines Eintrags vom Typ "directory", "zipfile" oder
eines anderen Eintrags vom Typ "sys.path" geladen wird.

In den übrigen Fällen "__main__.__spec__" ist auf "None" gesetzt, da
der Code, der zum Befüllen der "__main__" verwendet wird, nicht direkt
einem importierbaren Modul entspricht:

* interaktive Eingabeaufforderung

* "-c" Option

* Ausführung über stdin

* direkt aus einer Quell- oder Bytecode-Datei ausgeführt

Beachte, dass "__main__.__spec__" im letzten Fall immer "None" ist,
*selbst wenn* die Datei technisch gesehen stattdessen direkt als Modul
importiert werden könnte. Verwenden Sie den Schalter "-m", wenn
gültige Modul-Metadaten in "__main__" gewünscht sind.

Beachte außerdem, dass selbst wenn "__main__" einem importierbaren
Modul entspricht und "__main__.__spec__" entsprechend gesetzt ist,
diese dennoch als *unterschiedliche* Module betrachtet werden. Dies
liegt daran, dass Blöcke, die durch "if __name__ == "__main__":"
-Prüfungen geschützt sind, nur dann ausgeführt werden, wenn das Modul
zum Befüllen des Namensraums "__main__" verwendet wird, nicht jedoch
während eines normalen Imports.


5.9. Literaturverzeichnis
=========================

Die Importmechanismen haben sich seit den Anfängen von Python
erheblich weiterentwickelt. Die ursprüngliche Spezifikation für Pakete
kann nach wie vor eingesehen werden, auch wenn sich einige Details
seit der Erstellung dieses Dokuments geändert haben.

Die ursprüngliche Spezifikation für "sys.meta_path" war unter **PEP
302** zu finden und wurde später unter **PEP 420** erweitert.

**PEP 420** In Python 3.3 wurden *Namespace-Pakete* eingeführt.  In
der Version **PEP 420** wurde außerdem das Protokoll "find_loader()"
als Alternative zu "find_module()" eingeführt.

**PEP 366** beschreibt die Einführung des Attributs "__package__" für
explizite relative Importe in Hauptmodulen.

**PEP 328** führte absolute und explizite relative Importe ein und
schlug zunächst "__name__" als Semantik vor, die **PEP 366**
schließlich für "__package__" festlegen würde.

**PEP 338** definiert die Ausführung von Modulen als Skripte.

**PEP 451** fügt die Kapselung des Importstatus pro Modul in
Spezifikationsobjekten hinzu. Zudem werden die meisten Routineaufgaben
der Loader wieder auf die Importmechanismen verlagert. Diese
Änderungen ermöglichen die Abkündigung mehrerer APIs im Importsystem
sowie die Hinzufügung neuer Methoden zu Findern und Loadern.

-[ Fußnoten ]-

[1] Siehe "types.ModuleType".

[2] Die "importlib"-Implementierung vermeidet die direkte Verwendung
    des Rückgabewerts. Stattdessen wird das Modulobjekt abgerufen,
    indem der Modulname unter "sys.modules" nachgeschlagen wird. Dies
    hat indirekt zur Folge, dass ein importiertes Modul sich selbst
    unter "sys.modules" ersetzen kann. Dies ist ein
    implementierungsspezifisches Verhalten, dessen Funktionieren in
    anderen Python-Implementierungen nicht garantiert ist.
