2 Punkte von GN⁺ 2025-10-04 | 1 Kommentare | Auf WhatsApp teilen
  • In Python ist es gängige Praxis, Importe auf Modulebene vollständig zu deklarieren
  • Dadurch werden beim Programmstart jedoch oft auch unnötige Abhängigkeitsmodule sofort geladen, was zu Problemen bei Startgeschwindigkeit und Speicherverbrauch führt
  • Bisher wurden oft manuelle verzögerte Importe genutzt, etwa durch Importe innerhalb von Funktionen, aber das hat den Nachteil, dass Wartung und Abhängigkeitsverwaltung schwieriger werden
  • Dieses PEP 810 führt mit dem neuen lazy-Schlüsselwort, das local, explicit, controlled, granular ist, eine Syntax für explizite verzögerte Importe ein
  • Damit werden Module nur dann geladen, wenn sie tatsächlich benötigt werden, wodurch sich Startverzögerung und Speicherverschwendung verringern und zugleich die Transparenz der Codestruktur erhalten bleibt

Der aktuelle Stand von Python-Importen und ihre Probleme

  • In Python ist es weithin üblich, Import-Anweisungen ganz oben im Modul zu schreiben
  • Dieser Ansatz reduziert Duplikate, macht die Struktur der Import-Abhängigkeiten auf einen Blick erkennbar und minimiert den Runtime-Overhead, da nur einmal importiert wird
  • Wenn jedoch beim Programmstart das erste Modul (main) geladen wird, kommt es leicht zu Kettenimporten, bei denen auch viele tatsächlich ungenutzte Abhängigkeitsmodule sofort mit eingelesen werden
  • Gerade bei CLI-Tools entsteht unnötiger Overhead für jeden Subcommand, selbst wenn nur die Hilfe aufgerufen wird und dafür bereits Dutzende Module vorab geladen werden

Bisherige Alternativen und ihre Probleme

  • Häufig wird der Importzeitpunkt manuell hinausgezögert, indem Importe zum Beispiel in Funktionen verschoben werden
  • Diese Methode hat jedoch erhebliche Nachteile, etwa geringere Konsistenz und Wartbarkeit sowie eine schwierigere Übersicht über die gesamten Abhängigkeiten
  • Eine Analyse der Standardbibliothek zeigt, dass in performancekritischem Code bereits rund 17 % aller Importe zum Zweck des verzögerten Imports innerhalb von Funktionen oder Methoden verwendet werden
  • Es gibt Werkzeuge für verzögerte Importe wie importlib.util.LazyLoader oder das Third-Party-Paket lazy_loader, aber sie decken nicht alle Fälle ab oder es fehlt ein einheitlicher Standard

PEP 810: Einführung expliziter verzögerter Importe

  • Einführung des neuen Soft-Keywords lazy (hat nur in bestimmten Kontexten Bedeutung und kann auch als Variablenname verwendet werden)

  • lazy darf nur vor Import-Anweisungen verwendet werden und nicht in Bereichen wie Funktionen/Klassen/with/try oder bei star import

  • Es wird pro Import-Anweisung klar getrennt festgelegt und verzögert das Laden des Moduls bis zum tatsächlichen Nutzungszeitpunkt

    lazy import 모듈명
    lazy from 모듈명 import 이름
    

Implementierung expliziter verzögerter Importe und syntactic rule

  • Fälle mit Syntaxfehler:

    • innerhalb von Funktionen, innerhalb von Klassen, in try/with, bei star import (*) alles nicht erlaubt
  • Nutzungsbeispiel:

    import sys
    lazy import json
    print('json' in sys.modules)  # False (noch nicht geladen)
    result = json.dumps({"hello": "world"})  # Laden bei erster Verwendung
    print('json' in sys.modules)  # True (verzögertes Modul vollständig geladen)
    
  • Auf Modulebene kann das Attribut __lazy_modules__ als String-Liste verwendet werden, um Lazy-Ziele anzugeben

    __lazy_modules__ = ["json"]
    import json  # wird als lazy verarbeitet
    

Steuerung des Verhaltens über globale Flags und Filter

  • Mit globalen Flags oder Filterfunktionen lässt sich steuern, ob lazy auf Modulebene oder global angewendet wird

  • Mit einer Filterfunktion können Ausnahmen für eager import gezielt nur auf bestimmte Module angewendet werden

    def my_filter(importer, name, fromlist):
        if name in {'problematic_module'}:
            return False  # eager import
        return True  # lazy import
    sys.set_lazy_imports_filter(my_filter)
    

Runtime-Verhalten und Fehlerbehandlung

  • Bei Verwendung von lazy import erfolgt der tatsächliche Import nicht beim Import-Statement, sondern beim ersten Zugriff auf den Namen

  • Falls der Import fehlschlägt, werden durch Exception Chaining (traceback chaining) sowohl der Ort der Definition als auch der Ort des Fehlers klar angezeigt

    lazy from json import dumsp  # Tippfehler
    result = dumsp({"key": "value"})  # ImportError beim tatsächlichen Zugriff
    

Vorteile bei Speicher und Performance

  • Verzögerte Module erscheinen nur in der Menge sys.lazy_modules und werden vor der tatsächlichen Nutzung nicht in sys.modules eingetragen
  • Nach der Verwendung werden sie durch normale Modulobjekte ersetzt und können ohne zusätzliche Performance-Strafe genutzt werden
  • In realen Workload-Umgebungen zeigt sich eine Reduktion der Startverzögerung um 50–70 % und des Speicherverbrauchs um 30–40 %

Zusammenfassung der Funktionsweise

  • Beim ersten Zugriff auf ein lazy object erfolgt die reification (tatsächlicher Import und Ersetzung)
  • Greift externer Code auf das __dict__ eines Moduls zu, werden alle lazy objects zwangsweise geladen (reification)
  • Bei einem per globals() extrahierten Dictionary bleibt der lazy proxy erhalten, sodass ein direkter Zugriff nötig ist

Optimierung für Typannotationen und TYPE_CHECKING

  • Mit lazy from 모듈 import 이름 sind für Importe, die nur für Typen verwendet werden, ZERO Runtime-Kosten garantiert
  • Dadurch kann der bisherige Bedingungsblock mit from typing import TYPE_CHECKING ersetzt werden, was den Code knapper und klarer macht

Unterschiede zu PEP 690 und Implementierungsmerkmale

  • PEP 810 ist eine explizite Opt-in-Struktur pro einzelnem Import auf Basis einfacher Proxy-Objekte
  • PEP 690 war dagegen eine globale, implizite Struktur für lazy import

Hinweise und Interaktion zwischen Modulen

  • star import (*) wird von lazy nicht unterstützt (immer eager)
  • Custom import hook und loader funktionieren zum Zeitpunkt der reification unverändert weiter
  • Auch in Multithread-Umgebungen wird thread-safe garantiert, dass nur einmal importiert und sicher gebunden wird
  • Werden für dasselbe Modul lazy und eager gleichzeitig verwendet, hat eager immer Vorrang

Leitfaden für Anwendung im Code und Migration

  • Bei bestehendem Code wird empfohlen, per Profiling nur die wirklich nötigen Importe in lazy umzuwandeln und dies schrittweise einzuführen
  • Bei Verwendung von __lazy_modules__ besteht auch Kompatibilität mit Python-Versionen unter 3.15

Weitere wichtige Fragen und Antworten

  • Nebenwirkungen zur Importzeit (z. B. Registrierungsmuster) werden bis zum ersten Zugriff verzögert. Wenn solche side effects zwingend erforderlich sind, wird ein Muster mit expliziter Initialisierungsfunktion empfohlen
  • Das Problem von circular import kann durch lazy import nicht vollständig gelöst werden (es kann nur gemildert werden, wenn der Zugriff später erfolgt)
  • Die Hot-Path-Performance wird nach der ersten Verwendung automatisch optimiert, da der lazy-Check vollständig verschwindet (bytecode adaptive specialization)
  • In sys.modules wird das tatsächliche Modul erst nach der reification (erster Nutzung) eingetragen
  • Anders als bei importlib.util.LazyLoader ist keine separate Konfiguration nötig, die Performance bleibt erhalten, und die Standard-Syntax ist klarer

Fazit

  • PEP 810 ergänzt Python-Importe um das Schlüsselwort lazy und ermöglicht so in Bereichen wie Subcommand-CLI, großen Anwendungen und Typannotationen eine knappe und vorhersehbare Optimierung von Performanceproblemen durch unnötiges Laden von Modulen
  • Das neue Schlüsselwort erlaubt eine fein abgestimmte Festlegung von Einführungszeitpunkt und Zielobjekten und eignet sich damit in realen Services gut für schrittweise Einführung und Performance-Tuning
  • Als praktische Weiterentwicklung des Python-Importsystems erfüllt es gleichzeitig die drei Anforderungen Sichtbarkeit, Wartbarkeit und Performance

1 Kommentare

 
GN⁺ 2025-10-04
Hacker-News-Kommentare
  • Mein CLI-Tool llm.datasette.io unterstützt Plugins, aber es gab viele Beschwerden darüber, dass selbst Befehle wie llm --help eine viel zu langsame Startzeit haben. Bei der Untersuchung stellte sich heraus, dass populäre Plugins standardmäßig schwere Pakete wie pytorch importieren und dadurch den gesamten Start blockieren. Deshalb weise ich in der Dokumentation für Plugin-Autoren darauf hin, Abhängigkeiten nur dann innerhalb von Funktionen zu importieren, wenn sie wirklich gebraucht werden (passender Doku-Link). Aber es wäre deutlich besser, wenn Python so etwas auf Sprachebene unterstützen würde.

    • Man kann das noch heute direkt im Tool implementieren (Erklärung). Der Nachteil ist, dass dieser Ansatz global für den gesamten Prozess gilt. Wenn man also numpy verzögert importiert, werden auch alle Submodul-Importe verzögert. Am Ende wird numpy möglicherweise gar nicht importiert, wenn man nicht das Ganze braucht, aber stattdessen können sich partielle Modulimporte zu unvorhersehbaren Zeitpunkten über die gesamte Laufzeit verteilen. Weitere Experimente haben gezeigt, dass bei import foo.bar.baz foo und foo.bar weiterhin sofort geladen werden und nur foo.bar.baz verzögert wird. Das ist vermutlich ein Teil des Grundes, warum im PEP von „mostly“ die Rede ist. Wenn ich meine Implementierung weiter verbessere, könnte ich das vielleicht noch beheben.

    • Ich würde empfehlen, zuerst die Kommandozeile zu parsen, damit Optionen wie --help ohne Importe verarbeitet werden können. Importe dann nur ausführen, wenn sie wirklich nötig sind – oder einfacher gesagt: so entwerfen, dass erst dann importiert wird, wenn die einfachen Kommandooptionen abgearbeitet sind und noch Arbeit übrig ist.

  • Vorschläge für Lazy Imports gab es schon früher, zuletzt wurden sie 2022 abgelehnt (zugehörige Diskussion). Soweit ich mich erinnere, gibt es Lazy Imports bereits in Cinder, Metas CPython-Variante, und auch dieses PEP wird von Leuten vorangetrieben, die an Cinder gearbeitet haben. Im Mittelpunkt der Diskussion standen Fragen wie: „opt-in oder opt-out?“, „wie weit reicht die Anwendung?“ und „sollte das als CPython-Build-Flag kommen?“. Letztlich hat der Steering Council es wegen der Komplexität abgelehnt, weil sich das Importverhalten in zwei Varianten aufspaltet. Ich hoffe sehr, dass dieser Vorschlag diesmal durchkommt. Ich möchte diese Funktion wirklich benutzen.

    • Mir gefällt vor allem, dass es ein opt-in-Ansatz ist und sogar eine feingranulare Anwendung nach Ebenen sowie einen globalen Ausschalter enthält. Das ist innerhalb vieler Einschränkungen eine sehr gut ausgearbeitete Spezifikation.

    • Ich hoffe auch, dass der Vorschlag angenommen wird, bin aber nicht optimistisch. Das wird Unmengen an Code kaputtmachen und unerwartete Probleme hervorbringen. import-Anweisungen haben grundsätzlich Nebenwirkungen, und wenn sich ihr Ausführungszeitpunkt ändert, wird man lange unter Bugs leiden, deren Ursache man nicht versteht. Das ist keine Panikmache, sondern eine reale Sorge mit guten Gründen. Dass Lazy Imports bisher nur bei Meta eingeführt wurden, hat seinen Grund – man braucht ungefähr Metas Ressourcen, um so etwas beherrschen zu können. Viele Leute sehen nur „pandas, numpy oder mein verknotetes weirdes Modul sind zu langsam, also wäre schneller gut“, aber ich glaube, nur wenige verstehen überhaupt, wie Pythons Importsystem tatsächlich funktioniert. Es gibt sogar viele zustimmende Stimmen, die nicht einmal wissen, wie man Lazy Imports implementiert. Wenn man PEP 690 liest, sieht man etliche Nachteile – zum Beispiel geht Code kaputt, der mit Decorators Funktionen in ein zentrales Registry einträgt. Ein bekanntes Beispiel ist die Dash-Bibliothek, die JavaScript-basierte Interfaces und Python-Callbacks beim Importzeitpunkt per Decorator verknüpft; wenn Importe lazy werden, würde so ein Frontend komplett ausfallen. Auch Services mit sehr vielen Nutzern könnten sofort kaputtgehen. Dann heißt es zwar: „Es ist doch opt-in, wenn es nicht passt, schaltet man Lazy Imports eben aus.“ Aber was ist, wenn Importe transitiv sind? Oder wenn ein kritischer Prozess erst gestartet werden darf, nachdem das Frontend vollständig initialisiert wurde? Wer weiß schon, welche Auswirkungen das in einem Ökosystem hat, in dem Code und Bibliotheken vieler verschiedener Leute ineinandergreifen? Anders als Type Hints betrifft das die Laufzeit ganz konkret. import steht in praktisch jedem ernsthaften Python-Code, und mit Lazy Imports würde sich die grundlegende Ausführungsweise ändern. Dazu kommen noch weitere seltsame Fälle, die das PEP selbst erwähnt. Das Problem ist viel schwieriger, als es aussieht.

    • import torch==2.6.0+cu124, import numpy>=1.2.6 – so etwas wie versionsspezifizierte Importe, und die Möglichkeit, mehrere Versionen eines Pakets gleichzeitig in derselben Python-Umgebung zu installieren und zu importieren, wären wirklich großartig. Es wäre schön, wenn diese conda/virtualenv/docker/bazel-Hölle langsam enden würde.

  • Ich mag es nicht wirklich nicht, begrüße es aber auch nicht begeistert. So wie es jetzt aussieht, würde man wohl fast vor jedes import lazy schreiben, abgesehen von ein paar Fällen, in denen wirklich eager importiert werden muss. Dadurch wird der Code unübersichtlich. Und da nicht geplant ist, dieses Verhalten zum Standard zu machen, bleibt diese Umständlichkeit wohl für immer. Ich hätte ein System besser gefunden, bei dem das Modul selbst per opt-in deklariert, dass Lazy Loading erlaubt ist, und sich an der import-Syntax nichts ändert. Dann müssten sich nur große Bibliotheken mit Laziness beschäftigen. Natürlich hätte auch das Nachteile, etwa dass der Interpreter beim Import erst das Dateisystem durchsuchen müsste.

    • Wenn alle massenhaft Lazy Imports ohne besondere Probleme verwenden, dann hätte lazy eigentlich der Standard sein sollen und <i>eager</i> das optionale Schlüsselwort. Solche Paradigmenwechsel sind in Python nichts Neues. In v2 erzeugten verschiedene Konstrukte eager Listen, während sie in v3 zu Generatoren wurden, und das hat auch keine großen Probleme verursacht.

    • Wenn es ein Kommandozeilen-Flag gäbe, mit dem man alle Modulimporte in Python auf lazy stellen kann, würde ich es sofort benutzen. Abgesehen von Skripten oder wirklich einfachem Code ist es eigentlich ein schlechtes Muster, dass beim Laden eines Moduls Nebenwirkungen entstehen.

    • Ich finde nicht, dass das Modul entscheiden sollte, ob Lazy Loading verwendet wird. Nur der Aufrufer weiß, ob Lazy Loading gebraucht wird, deshalb ist es sinnvoll, die Option im importierenden Code anzugeben. Jedes Modul kann lazy geladen werden, und selbst bei Nebenwirkungen kann der Aufrufer gerade wollen, dass auch diese verzögert werden.

    • Ich fände es gut, wenn man in pyproject.toml per Regex Optionen für Lazy Loading angeben könnte.

    • In der Vergangenheit gab es bei neuen Features wie Type Hints, Walrus, asyncio, dataclasses usw. jedes Mal ähnliche Bedenken. Trotzdem haben nicht plötzlich alle Leute sie massenhaft verwendet oder alle bestehenden Muster umgestellt. Viele nutzen immer noch ungefähr den modernisierten Funktionsumfang eines Python 2.4, und sind damit völlig produktiv. Das läuft seit 20 Jahren gut, also wird es vermutlich kein großes Problem geben.

  • Falls es jemanden interessiert: lazyimp implementiert Lazy Imports in Form eines Context Managers sehr komfortabel. Normalerweise muss man import-Anweisungen nur in einen with-Block packen, was auch mit bestehendem Tooling gut zusammenspielt. Wenn man debuggen muss, kann man leicht wieder auf eager Imports umschalten. Über eine C-Extension ersetzt es f_builtins eines Frames und ist damit leistungsfähiger als ein importlib-Hook. Perfekt ist es nicht, aber es gibt auch eine threadsichere Version und eine mit globalem Handler. Anfangs war ich vorsichtig, aber inzwischen habe ich fast meine gesamte Codebasis darauf umgestellt. Es gab in der Praxis überhaupt keine Probleme – abgesehen davon, dass ich modulweises Registrieren nicht sauber berücksichtigt hatte – und der Geschwindigkeitsgewinn ist enorm, daher bin ich sehr zufrieden.

  • Es ist wirklich lästig, dass Python-Linter erzwingen, Importe an den Anfang einer Datei zu setzen. Immer wenn man die offensichtliche Implementierung für Lazy Imports benutzt, bekommt man Lint-Fehler. Das ist mehr als nur ein Performanceproblem. Wenn man zum Beispiel eine plattformspezifische Bibliothek braucht, möchte man sie vielleicht nur auf dieser Plattform importieren. Wenn Importe oben erzwungen werden, kann schon der Import selbst fehlschlagen.

    • Dann muss man den Linter eben anpassen, denke ich.

    • Die meisten Linter kann man mit Kommentaren wie #noqa E402 ignorieren.

  • Es heißt, über die Klasse LazyLoader seien bis zu einem gewissen Grad automatische Lazy Imports möglich. Allerdings ist die Nutzung der Python-Import-Interna so wenig offensichtlich, dass selbst die Erklärungen auf Stack Overflow nicht besonders lesbar sind (zugehörige Q&A). Deshalb habe ich selbst einen Proof of Concept gebaut, der ohne explizite Syntax alle Importe lazy macht.

import sys
import threading  # nötig in Python 3.13, zumindest in der REPL
from importlib.util import LazyLoader  # das muss unbedingt eager importiert werden!
class LazyPathFinder(sys.meta_path[-1]):  # erbt von _frozen_importlib_external.PathFinder
  @classmethod
  def find_spec(cls, fullname, path=None, target=None):
    base = super().find_spec(fullname, path, target)
    base.loader = LazyLoader(base.loader)
    return base
sys.meta_path[-1] = LazyPathFinder

Damit ersetzt man den Meta-Path-Finder durch einen Wrapper, der den Loader durch LazyLoader ersetzt. Wenn dann import ausgeführt wird, wird der Modulname zunächst tatsächlich an <class 'importlib.util._LazyModule'> gebunden, und erst beim Zugriff auf Attribute wird das echte Modul geladen. Testcode:

import this  # es passiert überhaupt nichts
print(type(this))  # <class 'importlib.util._LazyModule'>
rot13 = this.s  # Zen wird ausgegeben, an dieser Stelle wird das Modul geladen
print(type(this))  # <class 'module'>

Allerdings weiß ich nicht genau, was das „mostly“ im PEP konkret bedeuten soll.

  • Bei Lazy Imports scheint das Risiko für Thread-Sicherheit unterschätzt zu werden. Man kann überhaupt nicht vorhersagen, wann, in welchem Thread und unter welchen Locks ein Import ausgeführt wird; außer dem Importer-Lock ist nichts sicher. Früher lief gefährlicher Code beim Modulimport meist nur während einer weitgehend single-threaded Initialisierung, was das Problem begrenzte. Mit Lazy Imports würden Fehler auf wirklich unvorhersehbare Weise als Heisenbugs auftauchen. Imports auf Funktionsebene haben dieses Risiko zwar auch, aber dort gibt es wenigstens noch die Vorhersehbarkeit, dass sie explizit am Anfang eines klar sichtbaren Codepfads ausgeführt werden.

  • Wirkt auf mich wie ein gutes Feature: leicht zu erklären, mit echten Anwendungsfällen und einem vernünftigen Umfang (global sowie einfache Schlüsselwort-Variante). Gefällt mir.

    • Unter den neueren PEPs wirkt das aus Nutzersicht am aufgeräumtesten. Nach dem üblichen Syntax-Bikeshedding bin ich gespannt auf das tatsächliche Ergebnis.

    • Ich halte das für ein sehr sorgfältig vorbereitetes PEP: Prüfung von Praxis- und Edge-Case-Beispielen, sinnvolle Kompromisse, kein überzogener Ansatz und mehrfach nachgeschärft. Gerade weil hier ein Kernsystem einer großen Sprache mit sehr unterschiedlichen Communities weltweit angefasst wird, ist das ein riskanter Eingriff. Unter diesem Gesichtspunkt finde ich es besonders beeindruckend.

    • Hoffentlich hat man aus der Ablehnung von PEP 690 genug gelernt. Wir haben in unserer Codebasis auch versucht, so etwas selbst zu bauen, aber nie in einer Form, die wirklich brauchbar zuverlässig funktioniert hätte.

  • Die Gefahr bei Lazy Imports ist, dass in lang laufenden Services leicht unerwartete Laufzeitfehler entstehen. Der Vorteil eines schnellen Starts wirkt attraktiv, aber als Gegenleistung akzeptiert man, dass der Code mitten in der Ausführung wegen eines Importfehlers stehenbleiben kann. Außerdem können Edge Cases entstehen, in denen man beim Programmstart nicht mehr sicher sagen kann, was später überhaupt importiert wird.

    • Trotzdem ist das ein reales Problem, das unbedingt gelöst werden muss. Es geht nicht nur um Startup-Zeit; Python startet mit großen Abhängigkeiten teilweise absurd langsam. Große Projekte können nicht einfach für alle Nutzer sämtliche schweren Bibliotheken mitbündeln, selbst wenn diese nur ein Teil der Nutzer braucht. Deshalb greifen Entwickler bereits heute zu noch fragwürdigeren Workarounds, die wiederum neue absurde Probleme verursachen. Schon wenn nur die Unbequemlichkeit wegfällt, Funktions-Level-Imports mehrfach zu verstecken oder zu verschleiern, wäre das ein großer Fortschritt. Und vorgeschlagen ist das Ganze ja ausdrücklich nur als optionale Sprachfunktion.

    • Mit automatisierten Tests lässt sich das Risiko ausreichend abmildern; der Tausch gegen schnellere Startzeiten lohnt sich. Startup-Zeit ist keineswegs nur ein „kosmetisches“ Problem. Ich habe in einem Django-Monolithen erlebt, dass wegen nur einiger weniger schwerer Bibliotheken jeder Management-Befehl, jeder Test und jedes Container-Reload 10–15 Sekunden Wartezeit verursacht hat. Nachdem wir die Importe per Lazy Loading verzögert haben, war der Unterschied enorm.

  • Wir bevorzugen explizite Importe ganz oben, weil dadurch Abhängigkeitsprobleme direkt beim Start des Programms sichtbar werden. Mit Lazy Imports entdeckt man Probleme möglicherweise erst dann, wenn ein bestimmter Codepfad ausgeführt wird – vielleicht Stunden oder Tage später.

    • Umgekehrt würde ein automatisches Defer aller Importe bei kurzen Aufgaben die Ausführung von pip sofort beschleunigen.
$ time pip install --disable-pip-version-check
ERROR: You must give at least one requirement to install (see "pip help install")

real  0m0.399s
user  0m0.360s
sys   0m0.041s

Der Großteil der Zeit geht in Wahrheit dafür drauf, Vendor-Module zu importieren und wieder zu entladen, die gar nicht gebraucht werden (zum Beispiel fast 100 nur im Umfeld von Requests). Bei der Analyse zeigte sich, dass insgesamt mehr als 500 Module unnötig importiert werden.

  • Ich verstehe auch nicht, warum Codegeneratoren immer häufiger lokalen import innerhalb von Funktionen erzeugen statt Importe am Anfang. Ich würde dieses Muster nicht empfehlen, weil es die Abhängigkeiten eines Moduls schwerer erkennbar macht und das Risiko späterer zirkulärer Abhängigkeiten erhöht.

  • Ich habe das PEP noch nicht komplett gelesen, aber vielleicht wäre es gut, wenn es ein Kommandozeilen-Flag oder ein externes Tool zur Dependency-Validierung gäbe – ähnlich wie Werkzeuge rund um Type Hints.

  • Ich frage mich, wer mit „wir“ genau gemeint ist.

  • Sollte das nicht etwas sein, das man mit Tests abdeckt?