PEP 406 – Verbesserte Kapselung des Importstatus
- Autor:
- Alyssa Coghlan <ncoghlan at gmail.com>, Greg Slodkowicz <jergosh at gmail.com>
- Status:
- Zurückgezogen
- Typ:
- Standards Track
- Erstellt:
- 04-Jul-2011
- Python-Version:
- 3.4
- Post-History:
- 31-Jul-2011, 13-Nov-2011, 04-Dez-2011
Zusammenfassung
Diese PEP schlägt die Einführung einer neuen Klasse `ImportEngine` als Teil von importlib vor, die den gesamten Status im Zusammenhang mit dem Importieren von Modulen in einem einzigen Objekt kapselt. Das Erstellen neuer Instanzen dieses Objekts würde dann eine Alternative zum vollständigen Ersetzen der integrierten Implementierung der `import`-Anweisung durch Überschreiben der Funktion __import__() bieten. Um mit der integrierten Importfunktionalität und dem Importieren über Import-Engine-Objekte zu arbeiten, schlägt diese PEP einen kontextbasierten Ansatz vor, um den globalen Importstatus vorübergehend zu ersetzen.
Die PEP schlägt auch die Aufnahme einer Unterklasse `GlobalImportEngine` und einer global zugänglichen Instanz dieser Klasse vor, die "durchschreibt" zum prozessglobalen Status. Dies bietet eine abwärtskompatible Brücke zwischen der vorgeschlagenen gekapselten API und dem Legacy-Prozess-Global-Status und ermöglicht eine einfache Unterstützung für verwandte Statusaktualisierungen (z. B. selektives Ungültigmachen von Pfad-Cache-Einträgen, wenn sys.path geändert wird).
Rücknahme eines PEP
Das Importsystem hat seit der ursprünglichen Erstellung dieser PEP erhebliche Änderungen erfahren, als Teil von PEP 420 in Python 3.3 und PEP 451 in Python 3.4.
Während die Kapselung des Importstatus immer noch sehr wünschenswert ist, wird dies besser in einer neuen PEP mit PEP 451 als Grundlage angegangen und erlaubt nur die Verwendung von PEP 451-kompatiblen Findern und Loadern (da diese viele der Probleme der direkten Manipulation des globalen Status vermeiden, die mit der früheren Loader-API verbunden sind).
Begründung
Derzeit wird der meiste Status, der sich auf das Importsystem bezieht, als Modulattribute im Modul sys gespeichert. Die einzige Ausnahme ist der Import-Sperrmechanismus, der nicht direkt zugänglich ist, sondern nur über die zugehörigen Funktionen im Modul imp. Der aktuelle prozessglobale Importstatus umfasst
- sys.modules
- sys.path
- sys.path_hooks
- sys.meta_path
- sys.path_importer_cache
- der Import-Sperrmechanismus (imp.lock_held()/acquire_lock()/release_lock())
Die Isolierung dieses Status würde es ermöglichen, mehrere Importstatus innerhalb eines Prozesses bequem zu speichern. Das Platzieren der Importfunktionalität in einem eigenständigen Objekt würde auch das Unterklassen ermöglichen, um zusätzliche Funktionen hinzuzufügen (z. B. Benachrichtigungen über Modulimporte oder feinkörnige Kontrolle darüber, welche Module importiert werden können). Die Engine würde auch unterklassifiziert, um es zu ermöglichen, die Import-Engine-API zu verwenden, um mit dem bestehenden prozessglobalen Status zu interagieren.
Die Namespace-PEPs (insbesondere PEP 402) werfen einen potenziellen Bedarf an *zusätzlichem* prozessglobalem Status auf, um Paketpfade korrekt zu aktualisieren, wenn sys.path geändert wird.
Schließlich macht die Bereitstellung eines kohärenten Objekts für all diesen Status die Bereitstellung von Kontextverwaltungsfunktionen, die eine vorübergehende Ersetzung des Importstatus ermöglichen, machbar.
Vorschlag
Wir schlagen die Einführung einer `ImportEngine`-Klasse vor, um die Importfunktionalität zu kapseln. Dies beinhaltet eine `__import__()`-Methode, die als Alternative zur integrierten `__import__()`-Funktion verwendet werden kann, wenn dies gewünscht wird, und auch eine `import_module()`-Methode, die äquivalent zu importlib.import_module() ist [3].
Da es globale Invarianten des Importstatus gibt, die angenommen werden und beibehalten werden sollten, führen wir eine Klasse `GlobalImportState` mit einer Schnittstelle ein, die mit `ImportEngine` identisch ist, aber direkt auf den aktuellen globalen Importstatus zugreift. Dies kann leicht mithilfe von Klassen-Eigenschaften implementiert werden.
Spezifikation
ImportEngine API
Die vorgeschlagene Erweiterung besteht aus den folgenden Objekten
importlib.engine.ImportEngine
from_engine(self, other)Erstellt ein neues Importobjekt aus einer anderen `ImportEngine`-Instanz. Das neue Objekt wird mit einer Kopie des Status inotherinitialisiert. Wenn es auf `importlib engine.sysengine` aufgerufen wird, kann `from_engine()` verwendet werden, um ein `ImportEngine`-Objekt mit einer **Kopie** des globalen Importstatus zu erstellen.
__import__(self, name, globals={}, locals={}, fromlist=[], level=0)Neurealisierung der integrierten Funktion `__import__()`. Der Import eines Moduls erfolgt unter Verwendung des Status, der in der `ImportEngine`-Instanz gespeichert ist, anstatt des globalen Importstatus. Für eine vollständige Dokumentation der `__import__`-Funktionalität siehe [2]. `__import__()` aus `ImportEngine` und seinen Unterklassen kann verwendet werden, um das Verhalten der `import`-Anweisung anzupassen, indem `__builtin__.__import__` durch `ImportEngine().__import__` ersetzt wird.
import_module(name, package=None)Eine Neurealisierung von `importlib.import_module()`, die den in der `ImportEngine`-Instanz gespeicherten Importstatus verwendet. Siehe [3] für eine vollständige Referenz.
modules, path, path_hooks, meta_path, path_importer_cacheInstanzspezifische Versionen ihrer prozessglobalensys-Äquivalente
importlib.engine.GlobalImportEngine(ImportEngine)
Bequemlichkeitsklasse, um einen Engine-ähnlichen Zugriff auf den globalen Status zu ermöglichen. Bietet `__import__()`, `import_module()` und `from_engine()`-Methoden wie `ImportEngine`, schreibt aber durch zum globalen Status insys.
Zur Unterstützung verschiedener Namespace-Paketmechanismen sollten beim Ändern von sys.path Tools wie `pkgutil.extend_path` verwendet werden, um auch andere Teile des Importstatus zu ändern (in diesem Fall Paket `__path__`-Attribute). Der Pfad-Importer-Cache sollte auch bei einer Vielzahl von Änderungen ungültig gemacht werden.
Die `ImportEngine`-API bietet praktische Methoden, die verwandte Importstatusaktualisierungen automatisch als Teil einer einzigen Operation durchführen.
Globale Variablen
importlib.engine.sysengine
Eine vordefinierte Instanz von `GlobalImportEngine`. Gedacht für die Verwendung durch Importer und Loader, die aktualisiert wurden, um optionale `engine`-Parameter zu akzeptieren, und mit `ImportEngine.from_engine(sysengine)`, um mit einer Kopie des prozessglobalen Importstatus zu beginnen.
Keine Änderungen an den Finder/Loader-Schnittstellen
Anstatt zu versuchen, die PEP 302-APIs zur Unterstützung zusätzlicher Status zu aktualisieren, schlägt diese PEP vor, dass `ImportEngine` das Content-Management-Protokoll unterstützt (ähnlich den Kontext-Substitutionsmechanismen im Modul `decimal`).
Der Kontextverwaltungsmechanismus für `ImportEngine` würde
- Beim Eintritt: * Den Import-Sperrmechanismus erwerben * Den globalen Importstatus durch den eigenen Status der Import-Engine ersetzen
- Beim Austritt: * Den vorherigen globalen Importstatus wiederherstellen * Den Import-Sperrmechanismus freigeben
Die genaue API hierfür ist noch zu definieren (wird aber wahrscheinlich ein separates Kontextverwaltungsobjekt verwenden, ähnlich dem, das von `decimal.localcontext` erstellt wird).
Offene Fragen
API-Design für den Rückfall auf den globalen Importstatus
Der aktuelle Vorschlag beruht auf der `from_engine()`-API, um auf den globalen Importstatus zurückzufallen. Es kann wünschenswert sein, eine Variante anzubieten, die stattdessen dynamisch auf den globalen Importstatus zurückfällt.
Ein großer Vorteil des Beginns mit einem möglichst isolierten Design ist jedoch, dass es möglich wird, mit Unterklassen zu experimentieren, die die Grenzen zwischen dem Instanzstatus der Engine und dem prozessglobalen Status auf verschiedene Weise verwischen.
Builtin- und Erweiterungsmodule müssen prozessglobal sein
Aufgrund von Plattformbeschränkungen kann in jedem Prozess nur eine Kopie jedes integrierten und erweiterten Moduls leicht vorhanden sein. Daher ist es für jede `ImportEngine`-Instanz unmöglich, solche Module unabhängig zu laden.
Die einfachste Lösung besteht darin, dass `ImportEngine` sich weigert, solche Module zu laden, und `ImportError` auslöst. `GlobalImportEngine` könnte sie normal laden.
`ImportEngine` gibt solche Module immer noch aus einem vorab gefüllten Modul-Cache zurück – nur das direkte Laden verursacht Probleme.
Geltungsbereich der Ersetzung
Im Zusammenhang mit der vorherigen offenen Frage steht die Frage, welcher Status beim Verwenden der Kontextmanagement-API ersetzt werden soll. Es ist derzeit der Fall, dass das Ersetzen von `sys.modules` aufgrund von zwischengespeicherten Referenzen unzuverlässig sein kann, und es gibt die zugrundeliegende Tatsache, dass unabhängige Kopien einiger Module aufgrund von Plattformbeschränkungen einfach unmöglich sind.
Als Teil dieser PEP muss explizit dokumentiert werden
- Welche Teile des globalen Importstatus ersetzt werden können (und Code deklarieren, der Referenzen auf diesen Status speichert, ohne den Fall der Ersetzung fehlerhaft zu behandeln)
- Welche Teile in-place geändert werden müssen (und daher nicht durch die `ImportEngine`-Kontextmanagement-API ersetzt werden, oder anderweitig auf `ImportEngine`-Instanzen beschränkt sind)
Referenzimplementierung
Eine Referenzimplementierung [4] für einen früheren Entwurf dieser PEP, basierend auf Brett Cannons `importlib`, wurde von Greg Slodkowicz im Rahmen des Google Summer of Code 2011 entwickelt. Beachten Sie, dass die aktuelle Implementierung die bestehende Codebasis nicht ändert und daher viele Dinge unnötigerweise dupliziert. Eine tatsächliche Implementierung würde nur derart betroffenen Code in-place ändern.
Der frühere Entwurf der PEP schlug vor, die PEP 302-APIs so zu ändern, dass sie eine optionale Engine-Instanz unterstützen. Dies hatte den (ernsten) Nachteil, dass weitere Importe aus dem importierten Modul nicht korrekt beeinflusst wurden, daher die Änderung zum kontextbasierten Vorschlag für die Ersetzung des globalen Status.
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0406.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT