Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 366 – Explizite relative Importe im Hauptmodul

Autor:
Alyssa Coghlan <ncoghlan at gmail.com>
Status:
Final
Typ:
Standards Track
Erstellt:
01. Mai 2007
Python-Version:
2.6, 3.0
Post-History:
01. Mai 2007, 04. Juli 2007, 07. Juli 2007, 23. Nov. 2007

Inhaltsverzeichnis

Zusammenfassung

Diese PEP schlägt einen abwärtskompatiblen Mechanismus vor, der die Verwendung expliziter relativer Importe aus ausführbaren Modulen innerhalb von Paketen ermöglicht. Solche Importe schlagen derzeit aufgrund einer umständlichen Wechselwirkung zwischen PEP 328 und PEP 338 fehl.

Durch die Hinzufügung eines neuen Modulattributs ermöglicht diese PEP, dass relative Importe automatisch funktionieren, wenn das Modul mit dem Schalter -m ausgeführt wird. Eine geringe Menge an Boilerplate im Modul selbst ermöglicht es relativen Importen, zu funktionieren, wenn die Datei nach Namen ausgeführt wird.

Guido akzeptierte die PEP im November 2007 [5].

Vorgeschlagene Änderung

Die wichtigste vorgeschlagene Änderung ist die Einführung eines neuen Modulattributs, __package__. Wenn es vorhanden ist, werden relative Importe auf dieses Attribut anstatt auf das Modulattribut __name__ bezogen.

Wie beim aktuellen Attribut __name__ ist das Setzen von __package__ die Verantwortung des PEP 302-Loaders, der zum Importieren eines Moduls verwendet wird. Loader, die imp.new_module() zum Erstellen des Modulobjekts verwenden, erhalten das neue Attribut automatisch auf None gesetzt. Wenn das Importsystem auf einen expliziten relativen Import in einem Modul ohne gesetztes __package__ (oder mit None) trifft, wird es den korrekten Wert berechnen und speichern (__name__.rpartition('.')[0] für normale Module und __name__ für Paketinitialisierungsmodule). Wenn __package__ bereits gesetzt wurde, verwendet das Importsystem es vor der Neuberechnung des Paketnamens aus den Attributen __name__ und __path__.

Das Modul runpy setzt das neue Attribut explizit und bezieht sich dabei auf den Namen, der zum Auffinden des auszuführenden Moduls verwendet wird, anstatt auf den Namen, der zum Setzen des Attributs __name__ des Moduls verwendet wird. Dies ermöglicht, dass relative Importe aus Hauptmodulen, die mit dem Schalter -m ausgeführt werden, korrekt funktionieren.

Wenn das Hauptmodul nach seinem Dateinamen angegeben wird, wird das Attribut __package__ auf None gesetzt. Um relative Importe zu ermöglichen, wenn das Modul direkt ausgeführt wird, wäre Boilerplate ähnlich dem Folgenden vor der ersten Anweisung für einen relativen Import erforderlich

if __name__ == "__main__" and __package__ is None:
    __package__ = "expected.package.name"

Beachten Sie, dass diese Boilerplate nur dann ausreichend ist, wenn das Top-Level-Paket bereits über sys.path zugänglich ist. Zusätzlicher Code, der sys.path manipuliert, wäre erforderlich, damit die direkte Ausführung funktioniert, ohne dass das Top-Level-Paket bereits importierbar ist.

Dieser Ansatz hat auch den gleichen Nachteil wie die Verwendung von absoluten Imports von Geschwistermodulen – wenn das Skript in ein anderes Paket oder Unterpaket verschoben wird, muss die Boilerplate manuell aktualisiert werden. Der Vorteil ist, dass diese Änderung nur einmal pro Datei vorgenommen werden muss, unabhängig von der Anzahl der relativen Importe.

Beachten Sie, dass das explizite Setzen von __package__ auf einen leeren String erlaubt ist und dazu führt, dass alle relativen Importe aus diesem Modul deaktiviert werden (da die Importmaschinerie es in diesem Fall als Top-Level-Modul betrachtet). Das bedeutet, dass Tools wie runpy keine spezielle Behandlung für Top-Level-Module beim Setzen von __package__ bereitstellen müssen.

Begründung der Änderung

Die derzeitige Unfähigkeit, explizite relative Importe aus dem Hauptmodul zu verwenden, ist Gegenstand mindestens eines offenen SF-Bug-Reports (#1510172) [1] und war höchstwahrscheinlich ein Faktor bei mindestens einigen Anfragen auf comp.lang.python (wie Alan Isaacs Frage in [2]).

Diese PEP soll eine Lösung bieten, die explizite relative Importe aus Hauptmodulen ermöglicht, ohne signifikante Kosten beim Interpreterstart oder beim normalen Modulimport zu verursachen.

Der Abschnitt in PEP 338 über relative Importe und das Hauptmodul enthält weitere Details und Hintergrundinformationen zu diesem Problem.

Referenzimplementierung

Rev 47142 in SVN implementierte eine frühe Variante dieses Vorschlags, die den realen Modulnamen des Hauptmoduls im Attribut __module_name__ speicherte. Es wurde rückgängig gemacht, da 2.5 zu diesem Zeitpunkt bereits in der Beta-Phase war.

Patch 1487 [4] ist die vorgeschlagene Implementierung für diese PEP.

Alternative Vorschläge

PEP 3122 schlug vor, dieses Problem zu lösen, indem die Art und Weise geändert wird, wie das Hauptmodul identifiziert wird. Dies ist ein erheblicher Kompatibilitätsaufwand, um etwas zu beheben, das im Gesamtbild ein ziemlich geringfügiger Fehler ist, und die PEP wurde abgelehnt [3].

Der Vorteil des Vorschlags in dieser PEP ist, dass sein einziger Einfluss auf normalen Code die geringe Zeit ist, die benötigt wird, um das zusätzliche Attribut beim Importieren eines Moduls zu setzen. Relative Importe selbst sollten geringfügig beschleunigt werden, da der Paketname im globalen Bereich des Moduls zwischengespeichert wird, anstatt ihn für jeden relativen Import neu berechnen zu müssen.

Referenzen


Quelle: https://github.com/python/peps/blob/main/peps/pep-0366.rst

Zuletzt geändert: 2025-02-01 08:59:27 GMT