PEP 497 – Ein standardisierter Mechanismus für Abwärtskompatibilität
- Autor:
- Ed Schofield <ed at pythoncharmers.com>
- PEP-Delegate:
- Brett Cannon <brett at python.org>
- Status:
- Abgelehnt
- Typ:
- Prozess
- Erstellt:
- 04-Aug-2015
Ablehnungsbescheid
Der Lenkungsausschuss entschied, dass der __past__-Aspekt dieses Vorschlags zu kompliziert für den potenziellen Nutzen war. Der andere Aspekt, stärkere Anforderungen an die Abwärtskompatibilität, sollte durch PEP 387 behandelt werden.
Umfang
Diese PEP ist eine Ergänzung zu PEPs 5, 236 und 387 und verfolgt ähnliche Ziele.
Diese PEP erklärt die Notwendigkeit eines zusätzlichen Kompatibilitätsmechanismus zur Unterstützung von PEP 5, "Guidelines for Language Evolution". PEP 236, "Back to the __future__", führte einen Mechanismus für Vorwärtskompatibilität zur Unterstützung von PEP 5 ein, bemerkte jedoch, dass ein neuer Mechanismus für Abwärtskompatibilität außerhalb des Rahmens dieser PEP lag. Eine verwandte PEP (in Arbeit) führt einen solchen Mechanismus für Abwärtskompatibilität ein.
PEP 5, "Guidelines for Language Evolution", stellt fest, dass "Diese PEP [PEP 5] ersetzt oder schließt andere Kompatibilitätsstrategien wie das dynamische Laden von abwärtskompatiblen Parsern nicht aus."
Kontext
Aus PEP 236: "Von Zeit zu Zeit nimmt Python eine inkompatible Änderung an der beworbenen Semantik von Kernsprachkonstrukten vor oder ändert deren versehentliches (implementierungsabhängiges) Verhalten auf irgendeine Weise. Obwohl dies niemals willkürlich geschieht und immer mit dem Ziel geschieht, die Sprache langfristig zu verbessern, ist es kurzfristig umstritten und störend. PEP 5, Guidelines for Language Evolution, schlägt Wege vor, um den Schmerz zu lindern, und diese PEP [PEP 236] führt einige Mechanismen zur Unterstützung dessen ein."
Ebenfalls aus PEP 236: "Der Zweck von future_statement ist es, das Leben von Leuten zu erleichtern, die mit der neuesten Version rechtzeitig Schritt halten. Wir hassen Sie nicht, wenn Sie das nicht tun, aber Ihre Probleme sind viel schwerer zu lösen, und jemand mit diesen Problemen wird eine PEP schreiben müssen, die sie behandelt. future_statement richtet sich an ein anderes Publikum."
Die aktuelle Situation
Wenn eine inkompatible Änderung an der Kernsprachsyntax oder -semantik vorgenommen wird, bietet Python derzeit den future_statement-Mechanismus zur Gewährleistung der Vorwärtskompatibilität bis zur Version, die die neue Syntax oder Semantik erzwingt, aber keinen entsprechenden Standardmechanismus zur Gewährleistung der Abwärtskompatibilität nach dieser Version.
Problem
Eine Folge dieser Asymmetrie ist, dass in Bezug auf eine umwälzende Änderung die ältere (vor der Umwälzung) Version des Python-Interpreters fähiger ist als die neuere (umwälzende) Version; der ältere Interpreter kann sowohl Code verwenden, der vor der Änderung entworfen wurde, als auch neueren Code, während der neuere Interpreter nur Code verwenden kann, der zur Unterstützung des geänderten Features aktualisiert wurde.
Als Beispiel betrachten wir die Änderungen am Divisionsoperator, die in PEP 238 im Jahr 2001 eingeführt wurden, kurz nachdem PEP 236 den future_statement-Mechanismus eingeführt hatte. PEP 238 skizziert eine Reihe nützlicher Vorwärtskompatibilitätsmechanismen für die "echte Division" in der Python 2.x-Serie, versäumt es jedoch, nach der Erzwingung der "echten Division" in Python 3.0 irgendwelche Abwärtskompatibilitätsmechanismen einzuführen. Python-Versionen seit 3.0 bieten keinen Abwärtskompatibilitätsmechanismus wie from __past__ import division für Code, der die alten "klassischen Divisions"-Semantiken erwartet, während Python-Versionen vor 3.0 sowohl "klassischen Divisions"-Code als auch Vorwärtskompatibilität mit Code, der "echte Division" erwartet, unterstützen. Eine weitere Folge davon ist, dass der "kompatibelste" Interpreter in Bezug auf die Vielfalt des Divisions-bezogenen Python-Codes im Umlauf Python 2.7 ist, der Version vor der erzwingenden umwälzenden Änderung.
Abwärtskompatibilität als Wegbereiter für "Downhill-Upgrades"
Im Gegensatz zu dieser Situation sind neuere Versionen von Anwendungssoftware wie Office-Suiten tendenziell fähiger als frühere Versionen in Bezug auf ihre Unterstützung für das Laden unterschiedlicher Versionen ihrer Datenformatdateien. Das Muster ist normalerweise, dass die neueren Anwendungsversionen Daten sowohl aus ihren neueren als auch aus ihren älteren Datenformaten transparent laden können und dass die neuere Version standardmäßig Daten im neueren Format speichert. Neuere Anwendungssoftware-Versionen sind tendenziell standardmäßig abwärtskompatibel. Vorwärtskompatibilität ist relativ selten.
Diese Richtlinie verschafft dem Benutzer der neueren Anwendungssoftware einen Vorteil gegenüber dem Benutzer der älteren Software, die normalerweise nicht in der Lage ist, Daten im neueren Format zu laden. Manchmal ist es für einen Benutzer einer neueren Software-Anwendungsversion möglich, Daten in einer älteren Version zu exportieren, indem diese Option explizit gewählt wird. In diesen Fällen ist die damit ermöglichte Vorwärtskompatibilität möglicherweise nicht perfekt; einige Funktionen fehlen oder die Ergebnisse sind möglicherweise anderweitig suboptimal. Ein Upgrade ist daher einfach, während ein Downgrade schwieriger ist.
Das sich entwickelnde Verhalten bei vielen Benutzern einer solchen Richtlinie aus neuen attraktiven Funktionen plus Abwärtskompatibilitätsfunktionen führt dazu, dass ein natürlicher Druck auf jeden einzelnen Benutzer ausgeübt wird, seine eigene Anwendungsversion zu aktualisieren, und je mehr andere Benutzer, mit denen ein Einzelner Datendateien austauscht, desto akuter wird dieser Druck.
Vorschlag – Teil 1
Diese PEP macht zwei spezifische, verwandte Vorschläge. Der erste ist, dass
PEP 5 um einen 6. Schritt in der Sektion "Steps for Introducing Backwards-Incompatible Features" ergänzt wird, um anzuzeigen, dass, wenn eine inkompatible Änderung an der Kernsprachsyntax oder -semantik vorgenommen wird, die Politik von Python-dev darin besteht, vorzuziehen und zu erwarten, dass, wo immer möglich, ein Mechanismus für Abwärtskompatibilität für zukünftige Python-Versionen nach der standardmäßig übernommenen umwälzenden Änderung berücksichtigt und bereitgestellt wird, zusätzlich zu allen vorgeschlagenen Mechanismen für Vorwärtskompatibilität wie neuen future_statements. Darüber hinaus würde PEP 387, "Backwards Compatibility Policy" (falls akzeptiert), mit demselben 6. Schritt ergänzt werden.
Beispiel
Als Beispiel dafür, wie diese PEP angewendet werden soll, wäre die neueste Überarbeitung der PEP zur "echten Division" (238), wenn sie heute vorgeschlagen würde, als unvollständig betrachtet. PEP 238 weist auf die "schwerwiegenden Abwärtskompatibilitätsprobleme" hin, die der Vorschlag aufwirft, und beschreibt mehrere Maßnahmen für Vorwärtskompatibilität im Abstract und in den API-Änderungsabschnitten. Sie erwähnt auch einige auf c.l.py aufgeworfene Abwärtskompatibilitätsideen, darunter "Verwende from __past__ import division, um klassische Divisionssemantik in einem Modul zu verwenden", aber sie stellt keinen Abwärtskompatibilitätsplan als Teil des Vorschlags vor.
Wenn diese PEP akzeptiert wird, würde erwartet, dass ein Vorschlag wie PEP 238, aufgrund seiner weitreichenden Kompatibilitätsimplikationen, auch von einem Abwärtskompatibilitätsplan begleitet wird, der es Benutzern zukünftiger Python-Versionen nach Inkrafttreten der umwälzenden Änderung ermöglicht, das klassische Divisionsverhalten in ihrem Code leicht wieder zu aktivieren.
Vorschlag – Teil 2
Der zweite Vorschlag ist, dass
Python einen standardmäßigen Abwärtskompatibilitätsmechanismus parallel zum__future__-Modul-Mechanismus für Vorwärtskompatibilität bereitstellt.
Zur Referenz wird dieses Dokument hier als " __past__ "-Mechanismus bezeichnen, obwohl es nicht alle Eigenschaften des __future__-Moduls und des future_statement-Mechanismus haben muss.
Die spezifische Form und Implementierung des __past__-Mechanismus ist Gegenstand einer separaten PEP (in Arbeit). Diese PEP empfiehlt jedoch, dass dieser __past__-Mechanismus so konzipiert wird, dass er ähnliche Kriterien erfüllt wie die in PEP 296 für __future__ aufgeführten. Insbesondere
a. Er sollte es einzelnen Modulen ermöglichen, veraltete Verhaltensweisen anzugeben, die aus älteren Python-Versionen auf Modulbasis wieder aktiviert werden sollen.
b. Er sollte flexibel genug sein, damit sowohl Python 3.6+ als auch Punktversionen früherer Versionen die Abwärtskompatibilität mit älterer Python-Syntax oder -Semantik für Benutzer-Module, die den __past__-Mechanismus aufrufen, wieder einführen können.
c. Es sollte möglich sein, älteren Code, der so erweitert wurde, dass er __past__-Verhaltensweisen aufruft, auf älteren Python-Versionen wie 2.x auszuführen, die keine Kenntnis der spezifischen aufgerufenen __past__-Funktionen haben oder sogar, dass der __past__-Mechanismus für Abwärtskompatibilität existiert.
Gegenbeispiele
Einige Implementierungen von __past__-Mechanismen, die diese Kriterien verletzen würden, sind
a. Import-Hooks. Diese würden normalerweise nicht auf Modulbasis funktionieren; stattdessen gelten sie rekursiv für alle neuen Module, die aus einem Modul importiert werden.
b. Eine neue Syntax oder eine neue Semantik für Python 3.6, die mit früheren Versionen inkompatibel ist.
c. Eine Funktion, die in Python 3.6 zu einem Modul in der Python-Standardbibliothek hinzugefügt wird und unter demselben Namen in früheren Python-Versionen existiert.
Vorteile
Der Vorteil für Python-dev, diesen Vorschlag zu übernehmen, ist, dass zukünftige abwärtsinkompatible Änderungen weniger störend sein können, wenn diese Änderungen jeweils eine entsprechende __past__-Funktion haben, die implementiert ist und von Benutzern zukünftiger Python-Versionen leicht aufgerufen werden kann. Dies kann dazu beitragen, dass die Sprache schneller und effektiver weiterentwickelt wird, um Designfehler zu korrigieren.
Der Vorteil für konservative Benutzer ist offensichtlich: Sie können ihrem Code die Unterstützung für die neueste glänzende, kompatibilitätsbrechende Python-Version hinzufügen, indem sie lediglich eine __past__-Anweisung (vielleicht eine einzelne Zeile) zu jedem Modul hinzufügen, und dies kann automatisiert werden. Sie können dann ihren Interpreter auf die neueste Version aktualisieren und Zugriff auf die neuesten glänzenden Python-Funktionen erhalten.
Der Vorteil für die Community ist, dass, wenn zehntausend Benutzer auf Paket XYZ angewiesen sind und Paket XYZ trivial Unterstützung für die neueste Python-Version hinzufügen kann, diese zehntausend Benutzer ebenfalls schnell auf die neueste Python-Version aktualisieren können, ohne darauf warten zu müssen, dass Paket XYZ dies tut.
Fragen und Antworten
F1: Verlangt diese PEP, dass Python für jede abwärtsinkompatible Funktion dauerhaft zwei mögliche Semantik-Sätze beibehält?
A1: Absolut nicht. Legacy-Funktionen können immer noch ausgemustert werden, wenn es angemessen ist – das heißt, wenn die Mehrheit der Benutzerbasis zur neueren Python-Version migriert ist. Diese PEP schlägt lediglich vor, den Schwerpunkt der Entwicklungsbemühungen für Kompatibilität von 100 % Vorwärtskompatibilität auf mindestens 50 % Abwärtskompatibilität zu verlagern. Abwärtskompatibilität ist das mächtigere der beiden Konzepte, um es einer Benutzerbasis zu ermöglichen, die neueste Python-Interpreterversion zu übernehmen.
Man beachte, dass es schon lange her ist, seit die meisten Benutzer sich um Abwärtskompatibilität für nicht-verschachtelte Geltungsbereiche gekümmert haben, da die meisten Benutzer Python 2.1 bequem hinter sich gelassen haben.
F2: Aber Python-dev ist bereits überlastet und hat nicht die Bandbreite, die zusätzliche Komplexität zu implementieren / zu warten!
A2: Python-dev kann die Entwickler-Community bitten, sich zu engagieren und die Abwärtskompatibilität in Python für Legacy-Sprachfunktionen, die ihnen wichtig sind, zu pflegen. Wenn die Community ein bestimmtes veraltetes Verhalten nicht mehr unterstützt, kann Python-dev dies auch nicht mehr tun.
Der __past__-Mechanismus könnte möglicherweise so konzipiert werden, dass er von der Community erweiterbar ist, z. B. als Standard-, aber "gesegnetes" PyPI-Paket, um die Last für die Kernentwickler zu reduzieren.
F3: Werden Abwärtskompatibilitätsfunktionen nicht zu viel Geschwätz, Blähungen und Ballast in Python führen?
A3: Nicht unbedingt. Erstens könnten Vorschläge für neue, Kompatibilität brechende Funktionen in Python teilweise anhand der Einfachheit und Wartbarkeit der Implementierung ihrer zugehörigen __past__-Funktion im Voraus bewertet werden.
Zweitens sind einige alte Funktionen einfach bereitzustellen für Abwärtskompatibilität. Betrachten Sie das "klassische Divisions"-Verhalten vor Python 3.0. Das Projekt python-future enthält eine kompatible Implementierung der klassischen Division in der Funktion future.utils.old_div
def old_div(a, b):
"""
Equivalent to ``a / b`` on Python 2 without ``from __future__ import
division``.
"""
if isinstance(a, numbers.Integral) and isinstance(b, numbers.Integral):
return a // b
else:
return a / b
Die Bündelung einer solchen Funktion mit Python 3.x-Versionen, zusammen mit einem einfachen Mechanismus zur Aufrufung für jedes Auftreten von a / b nach einer entsprechenden __past__-Aufrufung, muss nicht mühsam sein.
F4: Was ist mit der Leistung? Wird die Leistung neuerer Python-Versionen unter der Last von Legacy-Funktionen leiden?
A4: Dies kann von Fall zu Fall bewertet werden. Die wichtigste potenzielle Sorge ist, dass die Leistung mit dem neuen Standardverhalten aufgrund der Präsenz der Legacy-Option nicht unangemessen leidet. Die Leistung unter dem Einfluss des __past__-Aufrufs ist von untergeordneter Bedeutung.
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0497.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT