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.


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.

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
-------------------

When the named module is not found in "sys.modules", Python next
searches "sys.meta_path", which contains a list of meta path finder
objects.  These finders are queried in order to see if they know how
to handle the named module.  Meta path finders must implement a method
called "find_spec()" which takes three arguments: a name, an import
path, and (optionally) a target module.  The meta path finder can use
any strategy it wants to determine whether it can handle the named
module or not.

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.

The "find_spec()" method of meta path finders is called with two or
three arguments.  The first is the fully qualified name of the module
being imported, for example "foo.bar.baz". The second argument is the
path entries to use for the module search.  For top-level modules, the
second argument is "None", but for submodules or subpackages, the
second argument is the value of the parent package's "__path__"
attribute. If the appropriate "__path__" attribute cannot be accessed,
a "ModuleNotFoundError" is raised.  The third argument is an existing
module object that will be the target of loading later. The import
system passes in a target module only during reload.

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: The "find_spec()" method of meta path finders
replaced "find_module()", which is now deprecated.  While it will
continue to work without change, the import machinery will try it only
if the finder does not implement "find_spec()".

Geändert in Version 3.10: Use of "find_module()" by the import system
now raises "ImportWarning".


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'):
       # It is assumed 'exec_module' will also be defined on the loader.
       module = spec.loader.create_module(spec)
   if module is None:
       module = ModuleType(spec.name)
   # The import-related module attributes get set here:
   _init_module_attrs(spec, module)

   if spec.loader is None:
       # unsupported
       raise ImportError
   if spec.origin is None and spec.submodule_search_locations is not None:
       # namespace package
       sys.modules[spec.name] = module
   elif not hasattr(spec.loader, 'exec_module'):
       module = spec.loader.load_module(spec.name)
       # Set __loader__ and __package__ if missing.
   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.

Neu 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. Module spec
------------------

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.

The module's spec is exposed as the "__spec__" attribute on a module
object. See "ModuleSpec" for details on the contents of the module
spec.

Neu in Version 3.4.


5.4.4. Import-related module attributes
---------------------------------------

The import machinery fills in these attributes on each module object
during loading, based on the module's spec, before the loader executes
the module.

__name__

   The "__name__" attribute must be set to the fully qualified name of
   the module.  This name is used to uniquely identify the module in
   the import system.

__loader__

   The "__loader__" attribute must be set to the loader object that
   the import machinery used when loading the module.  This is mostly
   for introspection, but can be used for additional loader-specific
   functionality, for example getting data associated with a loader.

__package__

   The module's "__package__" attribute must be set.  Its value must
   be a string, but it can be the same value as its "__name__".  When
   the module is a package, its "__package__" value should be set to
   its "__name__".  When the module is not a package, "__package__"
   should be set to the empty string for top-level modules, or for
   submodules, to the parent package's name.  See **PEP 366** for
   further details.

   This attribute is used instead of "__name__" to calculate explicit
   relative imports for main modules, as defined in **PEP 366**. It is
   expected to have the same value as "__spec__.parent".

   Geändert in Version 3.6: The value of "__package__" is expected to
   be the same as "__spec__.parent".

__spec__

   The "__spec__" attribute must be set to the module spec that was
   used when importing the module. Setting "__spec__" appropriately
   applies equally to modules initialized during interpreter startup.
   The one exception is "__main__", where "__spec__" is set to None in
   some cases.

   When "__package__" is not defined, "__spec__.parent" is used as a
   fallback.

   Neu in Version 3.4.

   Geändert in Version 3.6: "__spec__.parent" is used as a fallback
   when "__package__" is not defined.

__path__

   If the module is a package (either regular or namespace), the
   module object's "__path__" attribute must be set.  The value must
   be iterable, but may be empty if "__path__" has no further
   significance. If "__path__" is not empty, it must produce strings
   when iterated over. More details on the semantics of "__path__" are
   given below.

   Non-package modules should not have a "__path__" attribute.

__file__

__cached__

   "__file__" is optional (if set, value must be a string). It
   indicates the pathname of the file from which the module was loaded
   (if loaded from a file), or the pathname of the shared library file
   for extension modules loaded dynamically from a shared library. It
   might be missing for certain types of modules, such as C modules
   that are statically linked into the interpreter, and the import
   system may opt to leave it unset if it has no semantic meaning
   (e.g. a module loaded from a database).

   If "__file__" is set then the "__cached__" attribute might also be
   set,  which is the path to any compiled version of the code (e.g.
   byte-compiled file). The file does not need to exist to set this
   attribute; the path can simply point to where the compiled file
   would exist (see **PEP 3147**).

   Note that "__cached__" may be set even if "__file__" is not set.
   However, that scenario is quite atypical.  Ultimately, the loader
   is what makes use of the module spec provided by the finder (from
   which "__file__" and "__cached__" are derived).  So if a loader can
   load from a cached module but otherwise does not load from a file,
   that atypical scenario may be appropriate.


5.4.5. module.__path__
----------------------

By definition, if a module has a "__path__" attribute, it is a
package.

A package's "__path__" attribute is used during imports of its
subpackages. Within the import machinery, it functions much the same
as "sys.path", i.e. providing a list of locations to search for
modules during import. However, "__path__" is typically much more
constrained than "sys.path".

"__path__" must be an iterable of strings, but it may be empty. The
same rules used for "sys.path" also apply to a package's "__path__",
and "sys.path_hooks" (described below) are consulted when traversing a
package's "__path__".

A package's "__init__.py" file may set or alter the package's
"__path__" attribute, and this was typically the way namespace
packages were implemented prior to **PEP 420**.  With the adoption of
**PEP 420**, namespace packages no longer need to supply "__init__.py"
files containing only "__path__" manipulation code; the import
machinery automatically sets "__path__" correctly for the namespace
package.


5.4.6. 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.4: Use of "loader.module_repr()" has been
deprecated and the module spec is now used by the import machinery to
generate a module repr.For backward compatibility with Python 3.3, the
module repr will be generated by calling the loader's "module_repr()"
method, if defined, before trying either approach described above.
However, the method is deprecated.

Geändert in Version 3.10: Calling "module_repr()" now occurs after
trying to use a module's "__spec__" attribute but before falling back
on "__file__". Use of "module_repr()" is slated to stop in Python
3.12.


5.4.7. 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.

The path based finder iterates over every entry in the search path,
and for each of these, looks for an appropriate *path entry finder*
("PathEntryFinder") for the path entry.  Because this can be an
expensive operation (e.g. there may be "stat()" call overheads for
this search), the path based finder maintains a cache mapping path
entries to path entry finders.  This cache is maintained in
"sys.path_importer_cache" (despite the name, this cache actually
stores finder objects rather than being limited to *importer*
objects). In this way, the expensive search for a particular *path
entry* location's *path entry finder* need only be done once.  User
code is free to remove cache entries from "sys.path_importer_cache"
forcing the path based finder to perform the path entry search again
[3].

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).

To indicate to the import machinery that the spec represents a
namespace *portion*, the path entry finder sets
"submodule_search_locations" to a list containing the portion.

Geändert in Version 3.4: "find_spec()" replaced "find_loader()" and
"find_module()", both of which are now deprecated, but will be used if
"find_spec()" is not defined.Ä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()" takes one argument, the fully qualified name
of the module being imported.  "find_loader()" returns a 2-tuple where
the first item is the loader and the second item is a namespace
*portion*.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: Calls to "find_module()" and "find_loader()"
by the import system will raise "ImportWarning".


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.

If it is acceptable to only alter the behaviour of import statements
without affecting other APIs that access the import system, then
replacing the builtin "__import__()" function may be sufficient. This
technique may also be employed at the module level to only alter the
behaviour of import statements within that module.

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** introduced *namespace packages* for Python 3.3.  **PEP
420** also introduced the "find_loader()" protocol as an alternative
to "find_module()".

**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.

[3] In legacy code, it is possible to find instances of
    "imp.NullImporter" in the "sys.path_importer_cache".  It is
    recommended that code be changed to use "None" instead.  See
    Porting Python code for more details.
