Strategie, um mit (Python-) Sprachänderungen Schritt zu halten

16

Schreiben von Code, der noch in Jahren ausgeführt wird

Programmiersprachen ändern sich. Bibliotheken ändern sich. Einige Codes aus 5, 10 oder sogar 20 Jahren werden möglicherweise noch ausgeführt und führen zu erwarteten Ergebnissen, wohingegen Code aus 2 Jahren möglicherweise mit einem Syntaxfehler fehlschlägt. Dies ist teilweise unvermeidlich, da sich Sprachen entwickeln (zumindest die meisten). Entwickler sind dafür verantwortlich, ihren Code zu pflegen. Aber manchmal ist Stabilität eine wichtige Anforderung im Produktionscode, und Code sollte einfach 10 Jahre lang ausgeführt werden, ohne dass jemand den Code jedes Jahr durchgehen muss, um ihn an Sprachänderungen anzupassen. Oder ich habe kleine Skripte, zum Beispiel für die Analyse wissenschaftlicher Daten, die ich überprüfen muss, nachdem ich sie jahrelang nicht berührt habe. Zum Beispiel gibt es in meteorologischen Ämtern viel Fortran-Code, auch für nicht geschwindigkeitsentscheidende Teile, und die Codestabilität ist einer der Gründe. ICH' Ich habe gehört, dass die Angst vor Instabilität eines der Objekte ist, die sie gegen die Umstellung auf Python haben (abgesehen von der Trägheit der Sprache natürlich; dies ist nur für neuen Code möglich, der nicht von altem Code abhängig ist). Natürlich besteht eine Strategie für stabilen Code darin, das gesamte Betriebssystem einzufrieren. Das ist aber nicht immer machbar.

Ich verwende Python als Beispiel, aber das Problem ist nicht auf Python beschränkt.

Dokumente zu Python-Kompatibilitätsproblemen

Im Fall von Python gibt es mehrere Dokumente, in denen Richtlinien für inkompatible Änderungen aufgeführt sind.

PEP-5

Gemäß PEP 5 :

Zwischen der Veröffentlichung der Übergangsversion von Python und der Veröffentlichung der abwärtskompatiblen Version muss eine Übergangszeit von mindestens einem Jahr liegen. Die Benutzer haben mindestens ein Jahr Zeit, um ihre Programme zu testen und sie von der Verwendung des veralteten Konstrukts auf das alternative zu migrieren.

Persönlich halte ich ein Jahr für eher kurz. Das bedeutet, dass ich möglicherweise Code schreibe und in 1½ Jahren wird er nicht mehr ausgeführt.

PEP 291

PEP 291 enthält eine unvollständige Liste von Richtlinien für Dinge, die vermieden werden sollten, um die Abwärtskompatibilität aufrechtzuerhalten. Es bezieht sich jedoch nur auf Python 2.x. Da Python 2.7 das endgültige Release der 2.x-Reihe ist und Python 2.7 nur Bugfixes enthält, ist dieses PEP nur noch von historischem Interesse.

PEP 387

Es gibt auch PEP 387 zu abwärtskompatiblen Änderungen. PEP 387 ist ein Entwurf und keine offizielle Richtlinie. Im Juni 2009 wurde dies auf der Python-ideas-Mailingliste besprochen . Ein Teil der Diskussion konzentrierte sich darauf, wie Entwickler Code schreiben können, der robust gegen Sprachänderungen ist. Ein Beitrag listete einige Ratschläge auf, was nicht zu tun ist :

Daneben gibt es einige Regeln, aus denen Sie schließen können, dass sie die meiste Zeit wahrscheinlich zutreffen: Nennen "_"Sie keine Dinge, die mit beginnen , patchen Sie nichts, verwenden Sie keine dynamische Klassenersetzung für Objekte aus anderen Klassen als Ihren eigenen , hängen Sie nicht von der Tiefe der Vererbungshierarchien ab (z. B. nein ".__bases__[0].__bases__[0]"), stellen Sie sicher, dass Ihre Tests ohne DeprecationWarnings ausgeführt werden, und berücksichtigen Sie mögliche Namespace-Konflikte, wenn Sie Klassen Attribute hinzufügen, die von anderen Bibliotheken erben. Ich glaube nicht, dass all diese Dinge an einem Ort aufgeschrieben sind.

Darüber hinaus gab es einige Punkte zu "Minenfeldern" (neue Funktionen werden sich wahrscheinlich ändern) und "eingefrorenen Bereichen" (sehr verkaufte APIs werden sich garantiert nicht ändern). Zitiert von Antoine Pitrou :

Ich denke, der "eingefrorene Bereich" sollte eher positiv (explizite öffentliche APIs und explizit garantiertes Verhalten) als negativ (explizites "Minenfeld") definiert werden. Andernfalls werden wir vergessen, einige wichtige Dinge in das Minenfeld zu bringen und später gebissen zu werden, wenn wir diese Dinge auf eine inkompatible Weise ändern müssen.

Es scheint keine Schlussfolgerung aus diesem Thread zu geben, aber es kommt dem Kern dessen, was ich suche, ziemlich nahe. Der Thread ist fast vier Jahre alt, daher hat sich die Situation möglicherweise geändert oder verbessert. Welche Art von Code überlebt wahrscheinlich und welche Art von Code ist anfälliger?

Portierungsrichtlinien

Zusätzlich zu den oben beschriebenen Dokumenten enthält jede Python-Version eine Portierungsrichtlinie: Portierung auf Python 3.2 , Portierung auf Python 3.3 usw.

Nützliche Kompatibilität

PEP 3151 führte mich in das Konzept der nützlichen Kompatibilität ein . In meinen eigenen Worten läuft dies auf die Idee hinaus, dass Sprachentwickler nur dann vorsichtig sein müssen, wenn der Code sorgfältig geschrieben wurde, um die Kompatibilität aufrechtzuerhalten. Es definiert nicht wirklich nützliche Kompatibilität , aber ich denke, es ähnelt den Ideen, die ich aus der obigen Diskussion über PEP 387 zitiert habe.

Aus Sicht der Programmierer

Als Programmierer weiß ich, dass sich Python in Zukunft ändern wird und dass die Leute - vor allem ich - versuchen werden, meinen Code in einigen Jahren in einer Python-Version auszuführen, die eine, zwei oder vielleicht drei Nebenversionen enthält. Nicht alles wird kompatibel sein, und tatsächlich ist es einfach, Code zu finden, der fehlschlägt (ich bin einmal auf Code gestoßen, der angibt if sys.version[:3] != '2.3': print 'Wrong version, exiting'). Was ich suche ist eine Reihe von Leitlinien auf , was zu tun ist und was nicht zu tun , um die Chancen , dass mein Code noch unverändert in der Zukunft führen zu verbessern.

Gibt es solche Richtlinien? Wie schreibe ich Python-Code, der auch in Zukunft ausgeführt wird?

Meine Frage bezieht sich sowohl auf die Python - Kern, auf seine Standard - Bibliothek, sondern auch auf häufig verwendete Add-on - Bibliotheken, insbesondere numpy, scipy, matplotlib.


EDIT : Bisher beziehen sich zwei der Antworten auf Python2 vs. Python3. Das meine ich nicht. Ich kenne Tools für die Migration von Python2 nach Python3. Meine Frage bezieht sich auf die Sprachänderungen, die noch bevorstehen . Wir können besser als eine Kristallkugel Kodierungsrichtlinien finden, die stabiler sind. Beispielsweise:

  • import moduleist zukunftssicherer als from module import *, da letztere den Code beschädigen können, wenn moduleeine oder mehrere neue Funktionen / Klassen erweitert werden.

  • Die Verwendung undokumentierter Methoden ist möglicherweise weniger zukunftssicher als die Verwendung dokumentierter Methoden, da die Undokumentierung möglicherweise ein Zeichen dafür ist, dass etwas noch nicht stabil ist.

Es ist diese Art von praktischen Codierungsratschlägen, nach denen ich suche. Da es um Gegenwart → Zukunft geht, können wir uns auf Python3 beschränken, da sich Python2 nicht mehr ändern wird.

Gerrit
quelle

Antworten:

13

Dies ist ein ungelöstes Problem in unserem Bereich. Es gibt keine Möglichkeit, sicherzugehen, dass Ihr Code auf unbestimmte Zeit funktioniert. Auch wenn Ihr Code im vorwärtskompatiblen Sinne wirklich perfekt war (und wenn ja, bitte arbeiten Sie für mein Unternehmen!;)), Wenn er auf einer anderen Software ausgeführt wird, diese verwendet oder von einer anderen Software verwendet wird, die einen Fehler oder Änderungen aufweist In jedem Fall funktioniert Ihr Code möglicherweise nicht.

Daher kann ich Ihnen keine Liste von Dingen geben, die den Erfolg garantieren, wenn Sie sie befolgen. Sie können jedoch das Risiko zukünftiger Brüche minimieren und deren Auswirkungen minimieren. Ein sachkundigerer Pythonist kann Ihnen Ratschläge geben, die spezifischer für Python sind, daher muss ich allgemeiner vorgehen:

  • Unit-Tests schreiben. Sogar für Dinge, die du kennst, brauchst du sie nicht.

  • Verwenden beliebter / gut gestalteter / stabiler Bibliotheken und Technologien, um unbeliebte (und daher wahrscheinlich bald nicht mehr unterstützte) Bibliotheken zu vermeiden

  • Vermeiden Sie es, Code zu schreiben, der Implementierungsdetails ausnutzt. Code für Schnittstellen, keine Implementierungen. Code für mehrere Implementierungen derselben Schnittstelle. Führen Sie beispielsweise Ihren Code in CPython, Jython und IronPython aus und sehen Sie, was passiert. Dadurch erhalten Sie ein großartiges Feedback zu Ihrem Code. Dies ist jedoch für Python3 möglicherweise nicht hilfreich - zuletzt habe ich gehört, dass einige Implementierungen noch in Python2 vorhanden waren.

  • Schreiben Sie einfachen, klaren Code, der die Annahmen genau beschreibt

  • Schreiben Sie modularen, zusammensetzbaren Code. Wenn ein Code gefährlich sein muss (im Sinne der Zukunftssicherheit), trennen Sie ihn so, dass sich der Rest des Codes selbst dann nicht ändert, wenn er geändert werden muss.

  • haben eine Spezifikation von irgendeiner Form. Dies ähnelt den Punkten zu Komponententests, wenn Sie Tests als Spezifikation und Schnittstellen verwenden, die auch als Spezifikation verwendet werden können. (Ich meine Schnittstelle im allgemeinen Sinne, nicht den Java-Schlüsselwortsinn).

Wenn Sie eines dieser Dinge tun, kann sich der Arbeitsaufwand erhöhen, den Sie leisten müssen. Ich denke, das macht Sinn - viele dieser Punkte können auch für das Schreiben von gutem Code gemacht werden, was (meiner Meinung nach) ziemlich schwierig ist. Manchmal müssen Sie möglicherweise gegen einige dieser Vorschläge verstoßen. Das ist durchaus akzeptabel, aber achten Sie auf die Kosten.

Es ist großartig, dass das Python-Team darüber nachdenkt, und mit Sicherheit sind sie viel talentierter und geschickter als ich es jemals sein werde. Trotzdem würde ich davon ausgehen, dass der Code von irgendjemandem zu 100% nicht mehr so ​​funktioniert, wie er sein soll, wenn Python aktualisiert wird.


quelle
4

Es heißt Konfigurationsmanagement. Wenn das System niemals geändert wird, sollte es nicht kaputt gehen. Verändern Sie also nicht das System. Besorgt über neue Python-Versionen? Nicht upgraden. Besorgt über neue Gerätetreiber? Nicht upgraden. Besorgt über Windows-Patches? ...

Ross Patterson
quelle
0

Für Python 2 -> Python 3 ist bereits eine Python 2to3-Bibliothek installiert (im Lieferumfang des ursprünglichen Python-Pakets enthalten).

Auf dieser Grundlage sollte es bald nach der Veröffentlichung neuer Versionen ähnliche Bibliotheken geben, die mit jeder neuen Version geliefert werden. Wie Martijn sagte, werden solche Bibliotheken jedoch nur für Hauptversionen (wie Version 3.0), nicht aber für Nebenversionen (wie 3.2) freigegeben. Zwischen 3.0 und 3.2 (oder anderen Nebenversionen) sollten jedoch keine Kompatibilitätsprobleme auftreten. Daher sollte die Konvertierung in Version 3.0 in Ordnung sein.

Außerdem schlage ich vor, dass Sie sich diese Frage ansehen .

Rushy Panchal
quelle
1
Nein, mit 2to3 können Sie nur Code über die Hauptversionslücke hinweg aktualisieren. Es sind keine Bibliotheken (erforderlich) zum Aktualisieren von Code für kleinere Versionen vorhanden.
Martijn Pieters
@MartijnPieters Minor-Versionen sollten keine Kompatibilitätsprobleme aufweisen, da keine übermäßig großen Änderungen vorgenommen werden sollten. Bei Kompatibilitätsproblemen und großen Änderungen sollte eine komplett neue Version veröffentlicht werden.
0

Ich habe nicht viel hinzuzufügen, das "Programm für 2 und 2to3 verwenden" scheint in letzter Zeit eine verbreitete Ergänzung im Internet zu sein. Es gibt jedoch etwas, auf das Sie achten sollten:

Es heißt sechs (Pypi-Seite) . Es ist eine Python-Bibliothek, die dem Schreiben von Code für Python 2 und Python 3 gewidmet ist. Ich habe gesehen, dass sie in einer Reihe von Projekten zum Einsatz kam, als ich im Internet herumgesehen habe, aber die Namen sind mir im Moment entgangen.

Aren
quelle
Nicht wirklich das, wonach ich suche. Ich habe die Frage bearbeitet, hoffentlich ist klarer, wonach ich jetzt suche.
Gerrit