Die Möglichkeit, 4 Millionen Zeilen Python-Code zu überprüfen. Teil 1

Heute machen wir Sie auf den ersten Teil der Übersetzung des Materials darüber aufmerksam, wie Dropbox an der Typsteuerung von Python-Code beteiligt ist.



Dropbox schreibt viel in Python. Dies ist - die Sprache, die wir sehr gut nutzen - sowohl für die Back-End-Service und Desktop-Client-Anwendungen. Wir verwenden auch Go, TypeScript und Rust in großen Mengen, aber Python ist unsere Hauptsprache. In Anbetracht unserer Größe und der Tatsache, dass es sich um Millionen von Zeilen Python-Code handelt, stellte sich heraus, dass die dynamische Eingabe eines solchen Codes das Verständnis unnötig erschwerte und die Produktivität ernsthaft beeinträchtigte. Um dieses Problem zu mildern, begannen wir mit der schrittweisen Übertragung unseres Codes zu einer Überprüfung des statischen Typs mit mypy. Dies ist wahrscheinlich das beliebteste eigenständige Typprüfungssystem für Python. Mypy ist ein Open Source-Projekt, dessen Hauptentwickler bei Dropbox arbeiten.

Dropbox war eines der ersten Unternehmen, das eine statische Typprüfung in Python-Code in ähnlichem Umfang implementierte. Heutzutage wird mypy in Tausenden von Projekten verwendet. Dieses Tool ist eine unendliche Anzahl von Zeiten, wie sie sagen, „im Kampf getestet.“ Wir mussten einen langen Weg gehen, um dorthin zu gelangen, wo wir jetzt sind. Auf dem Weg gab es viele gescheiterte Ventures und gescheiterte Experimente. In diesem Material geht es um die Geschichte der statischen Typprüfung in Python - von ihrem sehr schwierigen Beginn, der Teil meines wissenschaftlichen Forschungsprojekts war, bis zum heutigen Tag, an dem unzähligen Entwicklern, die in Python schreiben, Typprüfungen und Typhinweise bekannt geworden sind. Diese Mechanismen werden jetzt von vielen Tools unterstützt, z. B. IDEs und Codeanalysatoren.

Lesen Sie den zweiten Teil

Warum ist eine Typprüfung notwendig?


Wenn Sie jemals eine dynamisch typisierte Python verwendet haben - können Sie einige Missverständnisse aus, warum um statische Typisierung und mypy in letzter Zeit so viel Lärm gestiegen. Und vielleicht gibt es eine Möglichkeit geben, dass Sie sich wie Python wegen seiner dynamischen Typisierung, und das passiert einfach frustrierend. Der Schlüssel zum Wert der statischen Typisierung ist der Umfang der Entscheidungen: Je größer Ihr Projekt ist, desto mehr neigen Sie zur statischen Typisierung und desto mehr brauchen Sie sie letztendlich wirklich.

Angenommen wurde ein Projekt mit einer Größe von Zehntausenden von Linien erreicht, und es stellte sich heraus, dass einige Programmierer arbeiten daran. In Anbetracht eines solchen Projekts können wir aufgrund unserer Erfahrung sagen, dass das Verständnis des Codes der Schlüssel zur Unterstützung der Entwicklerproduktivität ist. Ohne Typanmerkungen ist es beispielsweise nicht einfach herauszufinden, welche Argumente Sie an eine Funktion übergeben müssen oder welche Werte welche Typen eine Funktion zurückgeben kann. Hier sind typische Fragen, die ohne Verwendung von Typanmerkungen oft schwer zu beantworten sind:

  • Kann diese Funktion None ?
  • Was soll dieses Argument sein?
  • Was ist der Attributtyp id : int Dies ist str , oder vielleicht irgendeine Art von Benutzer?
  • Sollte dieses Argument eine Liste sein? Ist es möglich, ein Tupel hineinzugeben?

Wenn Sie sich das folgende Code-Snippet ansehen, das mit Typanmerkungen ausgestattet ist, und versuchen, solche Fragen zu beantworten, stellt sich heraus, dass dies die einfachste Aufgabe ist:

 class Resource:    id: bytes    ...    def read_metadata(self,                      items: Sequence[str]) -> Dict[str, MetadataItem]:        ... 

  • read_metadata gibt None nicht zurück, da der Rückgabetyp nicht Optional[…] .
  • Das Argument items ist eine Folge von Zeichenfolgen. Es kann nicht in zufälliger Reihenfolge wiederholt werden.
  • Das id Attribut ist eine Zeichenfolge von Bytes.

In einer idealen Welt würde man erwarten, dass alle diese Feinheiten in der eingebauten Dokumentation (docstring) beschrieben werden. Die Erfahrung gibt jedoch viele Beispiele dafür, dass eine solche Dokumentation im Code, mit dem Sie arbeiten müssen, häufig nicht beachtet wird. Selbst wenn eine solche Dokumentation im Code vorhanden ist, kann man nicht auf ihre absolute Richtigkeit zählen. Diese Dokumentation ist möglicherweise unklar und ungenau und bietet viele Möglichkeiten für Missverständnisse. In großen Teams oder in großen Projekten kann dieses Problem extrem akut werden.

Obwohl Python in der frühen oder mittleren Phase von Projekten eine gute Leistung erbringt, stellen erfolgreiche Projekte und Unternehmen, die Python verwenden, möglicherweise die entscheidende Frage: "Müssen wir alles in einer statisch typisierten Sprache umschreiben?"

Typprüfungssysteme wie mypy lösen das oben genannte Problem, indem sie dem Entwickler eine formale Sprache zur Beschreibung von Typen zur Verfügung stellen und prüfen, ob Typbeschreibungen mit Programmimplementierungen übereinstimmen (und optional auf ihre Existenz prüfen). Im Allgemeinen können wir sagen, dass diese Systeme uns mit einer Art bereitzustellen, gründlich in die Dokumentation geprüft.

Die Verwendung solcher Systeme hat andere Vorteile und ist bereits völlig trivial:

  • Typprüfung System kann einige kleine erkennen (wie auch - und nicht sehr klein) Fehler. Ein typisches Beispiel ist, wenn sie vergessen, den Wert None oder eine andere spezielle Bedingung zu verarbeiten.
  • Das Code-Refactoring wird erheblich vereinfacht, da das Typprüfungssystem häufig sehr genau meldet, welcher Code geändert werden muss. Zugleich brauchen wir nicht zu 100% Codeabdeckung zu hoffen, die in jedem Fall ist in der Regel nicht möglich. Wir müssen die Tiefe der Stack-Trace-Berichte nicht untersuchen, um die Ursache des Problems herauszufinden.
  • Auch große Projekte können oft mypy Scan-Typen in einem Bruchteil einer Sekunde verbringen. Und die Durchführung von Tests dauert normalerweise einige zehn Sekunden oder sogar Minuten. Das Typprüfsystem gibt dem Programmierer sofortiges Feedback und ermöglicht ihm, seine Arbeit schneller zu erledigen. Er muss keine fragilen und unterstützungsintensiven Unit-Tests mehr schreiben, die reale Entitäten durch Mokas und Patches ersetzen, um die Code-Testergebnisse schneller zu erhalten.

IDE und Editoren wie PyCharm oder Visual Studio-Code, um die Möglichkeit von Typenannotationen mit Möglichkeiten für Entwickler zur Verfügung zu stellen, um automatisch vervollständigen die auf Fehler Hervorhebungen, Unterstützung häufig verwendete Sprachkonstrukte. Und dies sind nur einige der Vorteile, die das Tippen bietet. Für einige Programmierer ist dies alles das Hauptargument für die Eingabe. Dies ist der Vorteil unmittelbar nach der Implementierung. Dieser Anwendungsfall Typen erfordern nicht die Verwendung einer einzigen Art von Testsystem, wie mypy, obwohl es zu beachten, dass mypy Einhaltung der Annotationstypen und Code zu erhalten hilft.

Mypy Hintergrund


Die mypy-Geschichte begann in Großbritannien in Cambridge, einige Jahre bevor ich zu Dropbox kam. Ich arbeitete als Teil der Doktorarbeit, die Frage der Vereinigung von statisch typisierten und dynamische Sprachen. Ich wurde von einem Artikel über die schrittweise Eingabe von Jeremy Siek und Walid Taha sowie dem Projekt Typed Racket inspiriert. Ich habe versucht, Wege zu finden, die gleiche Programmiersprache für eine Vielzahl von Projekten zu verwenden - von kleinen Skripten Code-Datenbanken aus vielen Millionen von Zeilen. Gleichzeitig möchte ich, dass ein Projekt jeder Größenordnung keine zu großen Kompromisse eingehen muss. Ein wichtiger Teil der all dies war die Idee, einen allmählichen Übergang von den Rohdaten des Prototyps Projekt gut getestet statisch typisierte Endprodukt. Heute werden diese Ideen weitgehend als selbstverständlich angesehen, aber 2010 war es ein Problem, das noch aktiv untersucht wurde.

Meine anfängliche Arbeit auf dem Gebiet der Typprüfung war nicht auf Python ausgerichtet. Stattdessen habe ich die kleine "hausgemachte" Sprache Alore verwendet . Hier ist ein Beispiel, das Sie verstehen können - was auf dem Spiel steht (Annotationstypen sind optional):

 def Fib(n as Int) as Int  if n <= 1    return n  else    return Fib(n - 1) + Fib(n - 2)  end end 

Die Verwendung einer vereinfachten Sprache unseres eigenen Designs ist ein gängiger Ansatz in der wissenschaftlichen Forschung. Dies liegt nicht zuletzt daran, dass Sie so schnell Experimente durchführen können, und auch daran, dass die Forschung irrelevant ist und frei ignoriert werden kann. Tatsächlich verwendete Programmiersprachen sind normalerweise großräumige Phänomene mit komplexen Implementierungen, was Experimente verlangsamt. Doch alle Ergebnisse auf einer vereinfachten Sprache basieren, schauen ein wenig verdächtig, seit dem Erhalt der Ergebnisse des Prüfers, durch Überlegungen gespendet kann, die für die praktische Anwendung der Sprache wichtig sind.

Mein Typprüfungstool für Alore sah sehr vielversprechend aus, aber ich wollte es testen, indem ich mit echtem Code experimentierte, der, wie man sagen könnte, nicht auf Alore geschrieben war. Zu meinem Glück wurde Alore Sprache auf den gleichen Ideen wie Python basiert weitgehend. Es war einfach genug, das Tool zur Typprüfung neu zu erstellen, damit es mit Python-Syntax und -Semantik funktioniert. Dies ermöglichte es uns, die Typprüfung in Open Source Python-Code zu versuchen. Außerdem habe ich einen Transporter geschrieben, um in Alore geschriebenen Code in Python-Code zu konvertieren, und damit den Code meines Typprüfungstools übersetzt. Jetzt habe ich ein System habe die Typen in Python geschrieben, um zu überprüfen, die Python Teilmenge unterstützt, eine Art von Sprache! (Bestimmte Architekturlösungen, die für Alore Sinn machten, waren für Python schlecht geeignet, was in einigen Teilen der mypy-Codebasis immer noch erkennbar ist.)

Tatsächlich unterstützte die Sprache, die von meinen Systemtypen, in diesem Moment ist es möglich, Python genannt zu werden: es ist eine Python-Version Annotationstypen Python 3 Syntax aufgrund einiger Einschränkungen war.

Es sah aus wie eine Mischung aus Java und Python:

 int fib(int n):    if n <= 1:        return n    else:        return fib(n - 1) + fib(n - 2) 

Eine meiner damaligen Ideen war es, Typanmerkungen zu verwenden, um die Leistung durch Kompilieren dieser Art von Python in C oder möglicherweise in JVM-Bytecode zu verbessern. Ich zog das Schreibens auf die Bühne, aber der Compiler Prototyp dieses Projekt verlassen, da die Typprüfung und in sich selbst sieht ganz nützlich.

Ich wiederum stellte mein Projekt PyCon Conference 2013 in Santa Clara. Ich habe darüber auch mit Guido van Rossum gesprochen, dem großzügigen lebenslangen Diktator von Python. Er überzeugte mich, meine eigene Syntax aufzugeben und mich an die Standard-Python 3-Syntax zu halten. Python 3 unterstützt Funktionsanmerkungen. Daher konnte mein Beispiel wie unten gezeigt umgeschrieben werden, um ein normales Python-Programm zu erhalten:

 def fib(n: int) -> int:    if n <= 1:        return n    else:        return fib(n - 1) + fib(n - 2) 

Ich musste einige Kompromisse eingehen (zunächst möchte ich darauf hinweisen, dass ich aus diesem Grund meine eigene Syntax erfunden habe). Insbesondere Python 3.3, die aktuellste Version der Sprache zu diesem Zeitpunkt, unterstützte keine variablen Anmerkungen. Ich habe mit Guido per E-Mail die verschiedenen Möglichkeiten zur Syntaxisierung solcher Anmerkungen besprochen. Wir entschieden uns für die variablen Kommentare Typen angibt, zu verwenden. Dadurch konnten wir unser Ziel erreichen, aber es sah etwas umständlich aus (Python 3.6 gab uns eine angenehmere Syntax):

 products = [] # type: List[str] # Eww 

Typkommentare waren auch für die Python 2-Unterstützung nützlich, da es keine integrierte Unterstützung für Typanmerkungen gibt:

 f fib(n):    # type: (int) -> int    if n <= 1:        return n    else:        return fib(n - 1) + fib(n - 2) 

Es stellte sich heraus, dass diese (und andere) Kompromiss in der Tat nicht wirklich wichtig - die Vorteile der statische Typisierung dazu geführt hat, dass die Nutzer bald über die nicht ganz ideal Syntax vergessen werden. Da es nun in Python-Code ist in der nicht kontrollierten Arten spezielle Syntax verwendet, Python bestehende Werkzeuge und Prozesse für die Verarbeitung des Code weiterhin normal arbeiten, die stark die Entwicklung eines neuen Tool-Entwickler erleichterte.

Guido überzeugte mich auch Dropbox zu verbinden, nachdem ich meine Diplomarbeit verteidigt. Hier beginnt der lustige Teil der Mypy-Geschichte.

Fortsetzung folgt…

Liebe Leser! Wenn Sie Python verwenden, teilen Sie uns bitte den Umfang der Projekte mit, die Sie in dieser Sprache entwickeln.


Source: https://habr.com/ru/post/de468233/


All Articles