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

Python Enhancement Proposals

PEP 762 – REPL-acing the default REPL

Autor:
Pablo Galindo Salgado <pablogsal at python.org>, Łukasz Langa <lukasz at python.org>, Lysandros Nikolaou <lisandrosnik at gmail.com>, Emily Morehouse-Valcarcel <emily at python.org>
Sponsor:
Pablo Galindo Salgado
Status:
Final
Typ:
Informational
Erstellt:
11-Okt-2024
Python-Version:
3.13

Inhaltsverzeichnis

Zusammenfassung

Eine der Kernstärken von Python ist sein interaktiver Modus, auch bekannt als Read-Eval-Print Loop (REPL), Python-Konsole oder Python-Shell. Dieses PEP beschreibt die neue Implementierung dieser Funktionalität, die in Python geschrieben ist. Die neue REPL, die in Python 3.13 veröffentlicht wird, zielt darauf ab, moderne Funktionen bereitzustellen, die von heutigen Benutzern erwartet werden, wie z. B. Mehrzeilenbearbeitung, Syntaxhervorhebung, benutzerdefinierte Befehle und eine insgesamt verbesserte interaktive Erfahrung.

Motivation

Bis Python 3.12 war die interaktive Shell von CPython in C als spezieller Modus des Parsers geschrieben. Daher war sie schwer zu warten und zu erweitern. Sie stützte sich auf die Existenz von GNU readline (oder einem Äquivalent) für grundlegende Funktionalitäten wie Cursorbewegung und Verlaufsspeicherung. Ohne diese Bibliothek kompiliertes Python bot einen interaktiven Modus mit sehr begrenzten Möglichkeiten. Auf der anderen Seite lagerte mit readline kompiliertes Python Entscheidungen und Konfigurationen bezüglich der Benutzereingabe aus, was die Erweiterung erschwerte.

Diese Komplexität hat Beiträge abgeschreckt und die Implementierung neuer Funktionen erschwert. Infolgedessen hat die interaktive Shell von CPython nur minimale Änderungen erfahren und ist hinter den Erwartungen der Benutzer an moderne Entsprechungen zurückgeblieben.

Viele Funktionen, die Benutzer von modernen REPLs erwarten, fehlten in der vorherigen Version. Einige Beispiele für diese Funktionen sind Mehrzeilenbearbeitung und -verlauf, benutzerdefinierte Befehle, Syntaxhervorhebung oder ergonomische Behandlung von Kopieren und Einfügen. Das Fehlen dieser Funktionen beeinträchtigt die Benutzererfahrung vieler Benutzergruppen von CPython erheblich, insbesondere in Umgebungen, in denen Benutzer keine Kontrolle über Abhängigkeiten haben und ihre eigenen Pakete nicht installieren können. Dies ist besonders häufig bei Benutzern, die die Sprache lernen, und bei Pädagogen der Fall.

Die Bewältigung solcher Probleme mit der C-Implementierung würde komplexe Workarounds erfordern, wie z. B. AST-Abgleiche von Befehlen, was die Komplexität der Codebasis prohibitiv erhöhen würde.

Mit der neuen REPL, die in Python geschrieben ist, begegnen wir diesen Einschränkungen und bringen die interaktive Erfahrung von CPython besser mit modernen Erwartungen und Fähigkeiten in Einklang.

Begründung

Die Implementierung der neuen REPL in Python anstelle von C hat die Einstiegshürde für Mitwirkende erheblich gesenkt. Diese Änderung hat es einfacher gemacht, die REPL zu testen, zu validieren und zu modifizieren, was zu verstärkter Beteiligung der Community und schnellerer Feature-Entwicklung führt. Die verbesserte Zugänglichkeit der Codebasis wird voraussichtlich zu einer sich schneller entwickelnden und benutzerfreundlicheren REPL führen.

Anstatt eine Python-REPL von Grund auf neu zu schreiben, haben wir uns entschieden, die Implementierung der neuen REPL auf PyREPL zu stützen. Diese Entscheidung wurde von mehreren Schlüsselfaktoren angetrieben. An erster Stelle ist die Entwicklung einer Terminalanwendung, die unter verschiedenen Betriebssystemen und Terminalemulatoren konsistent funktioniert, ein komplexes Unterfangen. Durch die Übernahme von PyREPL, das im PyPy-Projekt im Praxistest erprobt wurde, können wir auf bestehenden, bewährten Code zurückgreifen, anstatt bei Null anzufangen.

Die gemeinsame Nutzung einer Codebasis mit PyPy für die REPL-Implementierung bietet beiden Projekten gegenseitige Vorteile. Sie ermöglicht gemeinsame Wartungsbemühungen, schnellere Fehlerbehebungen und Funktionsverbesserungen, die den Benutzern von CPython und PyPy zugute kommen können. Diese Zusammenarbeit kann zu einer robusteren und funktionsreicheren REPL für das gesamte Python-Ökosystem führen.

Die vorherige in C geschriebene REPL nutzte die Bibliotheken „readline“ oder „editline“ als Backend, um bestimmte Funktionen wie Navigation, Verlaufsspeicherung und -abruf, Autovervollständigung und konfigurierbares Tastaturverhalten zu ermöglichen. PyREPL verwendet diese Bibliotheken nicht und implementiert die meisten anderen Funktionalitäten direkt als Teil der Shell. Die hauptsächlich fehlende Funktionalität (Konfigurierbarkeit der Eingabe) wird durch die Vorteile der neuen Architektur aufgewogen. Die Konfigurationsdateien für diese Bibliotheken (z. B. inputrc) sind komplex und enthalten Funktionen, die PyREPL nicht implementieren möchte, was eine transparente Unterstützung für sie in der neuen Shell unmöglich macht. Die Verwendung von „readline“ oder „editline“ in PyREPL wäre aufgrund der Mehrzeilenbearbeitung und der plattformübergreifenden Unterstützung prohibitiv komplex.

Obwohl dies bedeutet, dass bestehende readline/editline-Konfigurationen nicht mit PyREPL kompatibel sind, glauben wir, dass die erweiterten Funktionen und die verbesserte Erweiterbarkeit ein Gewinn sind. Siehe „Abwärtskompatibilität“ für die Diskussion der fortgesetzten Unterstützung für angepasste Arbeitsabläufe.

Die vorherige REPL machte es schwierig, benutzerdefinierte Befehle richtig zu implementieren, was eine sehr häufige Funktion interaktiver Shells ist. Zum Beispiel wurde der Befehl exit als Methodenaufruf eines benutzerdefinierten Objekts implementiert, das in den globalen Namensraum eingefügt wurde, was zu unintuitivem Verhalten führte, das Benutzer oft verwirrt, wenn sie einfach exit eingeben, da der Interpreter sie zur angeblich korrekten Verwendung exit() auffordert.

Spezifikation

PyREPL ist als neues privates Python-Modul namens _pyrepl implementiert, das neben der aktuellen C-Implementierung existiert. In seiner ersten Implementierung führt es die folgenden Hauptfunktionen ein:

  1. Mehrzeiliger Verlauf und Bearbeitung: Benutzer können ihren Befehlsverlauf über mehrere Zeilen hinweg navigieren und bearbeiten, was die Fähigkeit verbessert, komplexe Codeblöcke zu verfeinern und wiederzuverwenden.

    Die Bearbeitung von Mehrzeilenblöcken bietet automatische Einrückung mit vier Leerzeichen, was den Empfehlungen von PEP 8 entspricht. Wenn eine Zeile mit einem Doppelpunkt angetroffen wird, wird die folgende Zeile automatisch mit dem Einrückungsmuster eingerückt, das aus der ersten Zeile mit Einrückung abgeleitet wird. Zeilen werden mit vier Leerzeichen eingerückt und Tabs werden in Leerzeichen umgewandelt.

    Benutzer können auf den Verlauf von Befehlen zugreifen, indem sie die Pfeiltasten Oben und Unten verwenden. Innerhalb eines Mehrzeileneintrags navigieren die Pfeiltasten zeilenweise innerhalb des Blocks, bevor sie zum nächsten Verlaufseintrag wechseln. Die Pfeiltaste Unten funktioniert umgekehrt und navigiert von älteren Einträgen zu den aktuellsten.

    Der Verlauf kann vorwärts (mit Strg+S) und rückwärts (mit Strg+R) mit einer benutzerdefinierten Teilstring-Abfrage durchsucht werden. Er kann auch mit einer Präfixabfrage durchsucht werden, indem das Präfix in eine Shell-Zeile eingegeben und die Tasten BildAuf und BildAb verwendet werden.

  2. Kopieren und Einfügen: In unterstützten Terminalemulatoren wird die Funktion für das Einrahmen von Einfügungen erkannt und von PyREPL verwendet. Dies ermöglicht das transparente Einfügen von Codeblöcken, ohne dass es zu sofortiger Ausführung oder ungültiger automatischer Einrückung kommt.

    Für Terminalemulatoren, die diesen Modus nicht unterstützen, wird ein dedizierter Einfügemodus implementiert, um das einfache Einfügen von Mehrzeilencodeschnipseln zu ermöglichen, ohne sofortige Ausführung oder Einrückungsprobleme auszulösen.

    Benutzer treten manuell in den Einfügemodus ein, indem sie die Taste F3 drücken. Die Eingabeaufforderung ändert sich von >>> zu (einfügen), wo Benutzer Inhalte aus ihrer Zwischenablage einfügen oder wie gewünscht manuell eingeben können. Sobald der Inhalt bereit ist, beendet das Drücken von F3 den Einfügemodus. Dann führt das Drücken von Enter den Block aus.

    Benutzer können beim Einfügemodus mehrere Befehle in eine einzige Eingabe eingeben, was das Einfügen von Code aus anderen Quellen erleichtert.

    Um Codeblöcke ohne die führenden Eingabeaufforderungen und ohne die Ausgabe der Befehle zu kopieren, können Benutzer über die Taste F2 zur Verlaufansicht gelangen. Dieser Modus verwendet einen Pager, um den Verlauf der ausgeführten Befehle ohne Eingabeaufforderungen und Ausgabe anzuzeigen.

  3. Hilfe über F1.

    Der Zugriff auf das standardmäßige Hilfemodul ist über einen benutzerdefinierten Befehl help (siehe unten) oder über die Taste F1 möglich. Drücken Sie F1, um in den Hilfemodus zu gelangen. Wenn Sie fertig sind, drücken Sie F1 oder einen Standardbefehl (q, quit oder exit), um ihn zu beenden.

    Das Durchsuchen der interaktiven Hilfe behält keinen Befehlsverlauf.

  4. Benutzerdefinierte Befehle: Die REPL unterstützt die Implementierung benutzerdefinierter Befehle, wie z. B. exit, auf natürlichere und benutzerfreundlichere Weise, wodurch der aktuelle Workaround mit Funktionsaufrufen vermieden wird.

    Die anfängliche Liste der benutzerdefinierten Befehle umfasst

    • exit
    • quit
    • copyright
    • help
    • clear

    Befehle sind verfügbar, solange kein Namenskonflikt mit einer Variable in einem erreichbaren Bereich besteht. Wenn Sie beispielsweise exit = 1 zuweisen, hat die Variable Vorrang vor PyREPL-Befehlen. del exit entfernt in diesem Fall den Konflikt und der Befehl funktioniert wieder.

  5. Farben: Die Eingabeaufforderungen sowie bestimmte Elemente der Ausgabe, wie z. B. Ausnahmetracebacks, sind jetzt farbig. Farben können mit der Standardumgebungsvariable NO_COLOR deaktiviert oder mit der Standardumgebungsvariable FORCE_COLOR erzwungen werden. Eine spezifische Python-Umgebungsvariable ist ebenfalls verfügbar, nämlich PYTHON_COLORS. Die anfängliche Implementierung in Python 3.13 bietet keine Anpassung des Farbschemas.

Diese Funktionen verbessern die interaktive Python-Erfahrung erheblich und bringen sie stärker in Einklang mit modernen Entwicklungsumgebungen und Benutzererwartungen. Die Implementierung erfolgt in Python und bietet mehrere Vorteile:

  1. Einfacheres Testen und Validieren: Das Schreiben von Tests für Python-Code ist deutlich einfacher und unkomplizierter als für C-Code, was eine umfassendere Testabdeckung aller vorhandenen und alten Funktionen ermöglicht.
  2. Niedrigere Beitragsschwelle: Pythons Zugänglichkeit im Vergleich zu C ermutigt zu mehr Community-Beiträgen, was zu schnellerer Feature-Entwicklung und Fehlerbehebung führt.
  3. Flexibilität: Eine Python-Implementierung ist einfacher zu erweitern und zu modifizieren, was die Entwicklungsgeschwindigkeit bei neuen Funktionen und Verbesserungen sowohl für Kernentwickler als auch für Mitwirkende verbessert.

Abwärtskompatibilität

Die PyREPL-Implementierung ist so konzipiert, dass die vollständige Abwärtskompatibilität mit vorhandenem Python-Code gewahrt bleibt, da die alte Basis-REPL als Fallback erhalten bleibt und bei Bedarf verfügbar ist, falls benutzerdefinierte Arbeitsabläufe dies erfordern. Sie wird auch in Fällen verwendet, in denen die neue REPL aufgrund von Umgebungsbeschränkungen oder anderen Problemen nicht verwendet werden kann. Benutzer haben die Möglichkeit, die alte Basis-REPL explizit auszuwählen, indem sie die Umgebungsvariable PYTHON_BASIC_REPL auf 1 setzen. Dies stellt sicher, dass Benutzer die vertraute Benutzeroberfläche und die Funktionalität weiterhin nutzen können, wenn sie dies bevorzugen oder auf Probleme mit der neuen Implementierung stoßen.

Es ist wichtig zu betonen, dass die Einführung von PyREPL keine vorhandene Funktionalität entfernt. Jede Funktionalität der alten Basis-REPL, die in PyREPL nicht verfügbar ist, wird in der alten Basis-REPL beibehalten und gepflegt, die von den Benutzern als Fallback verwendet werden kann.

Insbesondere Benutzer, die ihre benutzerdefinierten Eingabekonfigurationen in inputrc- oder editrc-Dateien weiterhin verwenden möchten, können die alte Basis-REPL weiter nutzen.

Die Autoren erwarten keine Portierung von PyREPL-Funktionalitäten zur alten Basis-REPL. Ebenso ist die Unterstützung von inputrc und editrc in PyREPL explizit nicht geplant. Diese Konfigurationsdateien werden von den „readline“- und „editline“-Bibliotheken bereitgestellt und geparst, und ihr Funktionsumfang stimmt nicht mit der Funktionalität überein, die PyREPL anstrebt.

Um einen reibungslosen Übergang zu ermöglichen, wird eine klare Dokumentation bereitgestellt, wie zwischen PyREPL und der alten Basis-REPL umgeschaltet wird.

Dieser Ansatz stellt sicher, dass wir zwar signifikante Verbesserungen mit der neuen REPL einführen, aber keine sofortigen Änderungen auf Benutzer erzwingen, die auf der aktuellen Implementierung basieren. Der Fallback-Mechanismus und die Option zur Benutzerwahl bieten ein Sicherheitsnetz, das eine schrittweise Einführung der neuen REPL ermöglicht und gleichzeitig alle vorhandenen Funktionalitäten beibehält.

Sicherheitsimplikationen

Aus diesem Vorschlag ergeben sich keine Sicherheitsimplikationen.

Wie man das lehrt

Die Einführung von PyREPL wird von Dokumentation und Tutorials begleitet. Schwerpunkte der Schulung werden sein:

  1. Detaillierte Erklärungen zur Verwendung von Mehrzeilenbearbeitung, Einfügemodus und anderen neuen Funktionen.
  2. Benutzerdefinierte Befehle (bestehende und neue).
  3. So wechseln Sie zur neuen REPL, einschließlich aller Unterschiede zur vorherigen readline/editline-basierten Konfiguration.

Abgelehnte Ideen

Mehrere alternative Ansätze wurden in Betracht gezogen und schließlich verworfen:

  1. Erweiterung der aktuellen C-Implementierung: Obwohl dies die maximale Abwärtskompatibilität gewahrt hätte, wurde dies als zu komplex eingestuft und hätte die grundlegenden Einschränkungen nicht behoben, die oben beschrieben wurden.
  2. Entwicklung einer neuen REPL von Grund auf: Dieser Ansatz wurde aufgrund der Komplexität der Erstellung einer plattformübergreifenden Terminalanwendung und des Wunsches, auf bestehenden, erprobten Code zurückzugreifen, verworfen.
  3. Verwendung anderer vorhandener REPL-Implementierungen: Die Autoren sahen sich mehrere Alternativen an, wie z. B. IPython, bpython, ptpython und xonsh. Während all die oben genannten beeindruckende Projekte sind, wurde letztendlich PyREPL aufgrund seiner Kombination aus Reife, Funktionsumfang und fehlenden zusätzlichen Abhängigkeiten gewählt. Ein weiterer wichtiger Faktor war die Übereinstimmung mit der Implementierung von PyPy.

Danksagungen

Vielen Dank an Diego Russo für das Feedback zu Entwürfen dieses PEP.


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

Zuletzt geändert: 2025-02-01 07:28:42 GMT