{"id":38479,"date":"2019-10-31T22:23:56","date_gmt":"2019-10-31T19:23:56","guid":{"rendered":"https:\/\/prohoster.info\/blog\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\/"},"modified":"2019-10-31T22:23:56","modified_gmt":"2019-10-31T19:23:56","slug":"put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","status":"publish","type":"post","link":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","title":{"rendered":"Der Weg zur \u00dcberpr\u00fcfung von 4 Millionen Zeilen Python-Code. Teil 2","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Heute ver\u00f6ffentlichen wir den zweiten Teil der \u00dcbersetzung des Materials dar\u00fcber, wie Dropbox die Typenkontrolle f\u00fcr mehrere Millionen Zeilen Python-Code organisiert hat.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\"><img decoding=\"async\" alt=\"Der Weg zur \u00dcberpr\u00fcfung von 4 Millionen Zeilen Python-Code. Teil 2\" src=\"\/wp-content\/uploads\/2019\/09\/3f8f396d724153a0374a3fadca190d55.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p>\u2192 <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468233\/\">Erste Teil lesen<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Offizielle Unterst\u00fctzung f\u00fcr Typen (PEP 484)<\/h2>\n<p>\nW\u00e4hrend der Hack Week 2014 haben wir in Dropbox erste ernsthafte Experimente mit mypy durchgef\u00fchrt. Die Hack Week ist eine Veranstaltung, die Dropbox eine Woche lang abhalten kann. In dieser Zeit k\u00f6nnen Mitarbeiter an allem arbeiten, was sie wollen! Einige der bekanntesten Technologieprojekte von Dropbox haben genau in solchen Veranstaltungen ihren Anfang genommen. Aus diesem Experiment zogen wir die Schlussfolgerung, dass mypy vielversprechend aussieht, auch wenn dieses Projekt noch nicht f\u00fcr den breiten Einsatz bereit war.<\/p>\n<p>Zu dieser Zeit kursierte die Idee einer Standardisierung der Typ-Hinweis-Systeme von Python. Wie bereits erw\u00e4hnt, konnten ab Python 3.0 Typannotationen f\u00fcr Funktionen verwendet werden, aber es handelte sich lediglich um willk\u00fcrliche Ausdr\u00fccke, ohne festgelegte Syntax und Semantik. W\u00e4hrend der Programmausf\u00fchrung wurden diese Annotationen gr\u00f6\u00dftenteils einfach ignoriert. Nach der Hack Week begannen wir mit der Arbeit an der Standardisierung der Semantik. Diese Arbeit f\u00fchrte zur Entstehung von <noindex><a rel=\"nofollow\" href=\"https:\/\/www.python.org\/dev\/peps\/pep-0484\/\">PEP 484<\/a><\/noindex> (An diesem Dokument arbeiteten Guido van Rossum, \u0141ukasz Langa und ich gemeinsam).<\/p>\n<p>Unsere Motive k\u00f6nnen aus zwei Perspektiven betrachtet werden. Zum einen hofften wir, dass das gesamte Python-\u00d6kosystem einen einheitlichen Ansatz f\u00fcr die Verwendung von Typanmerkungen (type hints \u2013 ein Begriff, der in Python als \u00c4quivalent zu \u201aTypanmerkungen\u2018 verwendet wird) akzeptieren k\u00f6nnte. Dies w\u00e4re in Anbetracht m\u00f6glicher Risiken besser, als mit einer Vielzahl von nicht kompatiblen Ans\u00e4tzen zu arbeiten. Zum anderen wollten wir die Mechanismen der Typanmerkung offen mit vielen Vertretern der Python-Community diskutieren. Teilweise wurde dieser Wunsch dadurch motiviert, dass wir nicht als \u201aAbtr\u00fcnnige\u2018 von den grundlegenden Ideen der Sprache in den Augen der breiten Masse der Python-Entwickler erscheinen wollten. Es handelt sich um eine dynamisch typisierte Sprache, die f\u00fcr ihre \u201aEnten-Typisierung\u2018 bekannt ist. Zu Beginn gab es in der Gemeinschaft eine gewisse Skepsis gegen\u00fcber der Idee der statischen Typisierung. Doch diese Einstellung schw\u00e4chte sich schlie\u00dflich ab, nachdem klar wurde, dass die statische Typisierung nicht verpflichtend gemacht werden sollte (und nachdem die Leute erkannten, dass sie tats\u00e4chlich n\u00fctzlich ist).<\/p>\n<p>Der angenommene Syntax f\u00fcr Typ-Hinweise \u00e4hnelte stark dem, was zu dieser Zeit von mypy unterst\u00fctzt wurde. Das Dokument PEP 484 wurde zusammen mit Python 3.5 im Jahr 2015 ver\u00f6ffentlicht. Python war nicht l\u00e4nger eine Sprache, die nur dynamische Typisierung unterst\u00fctzte. Ich betrachte diesen Moment als einen bedeutenden Meilenstein in der Geschichte von Python.<\/p>\n<h2>Beginn der Migration<\/h2>\n<p>\nEnde 2015 wurde bei Dropbox ein Team von drei Personen gegr\u00fcndet, um an mypy zu arbeiten. Dazu geh\u00f6rten Guido van Rossum, Greg Price und David Fischer. Von diesem Zeitpunkt an entwickelte sich die Situation sehr schnell. Das erste Hindernis f\u00fcr das Wachstum von mypy war die Leistung. Wie ich bereits angedeutet habe, dachte ich in der fr\u00fchen Phase der Entwicklung des Projekts dar\u00fcber nach, die Implementierung von mypy in C zu \u00fcbersetzen, aber diese Idee wurde vorerst von der Liste gestrichen. Wir waren darauf angewiesen, dass das System mit dem CPython-Interpreter betrieben wurde, der nicht die Geschwindigkeit aufwies, die f\u00fcr Werkzeuge wie mypy erforderlich ist. (Das PyPy-Projekt, eine alternative Implementierung von Python mit einem JIT-Compiler, half uns auch nicht weiter.)<\/p>\n<p>Zum Gl\u00fcck haben uns einige algorithmische Verbesserungen unterst\u00fctzt. Der erste starke \u201eBeschleuniger\u201c war die Implementierung einer inkrementellen Pr\u00fcfung. Die Idee dieser Verbesserung war einfach: Wenn sich alle Abh\u00e4ngigkeiten eines Moduls seit dem letzten Start von mypy nicht ge\u00e4ndert haben, k\u00f6nnen wir w\u00e4hrend der Arbeit mit den Abh\u00e4ngigkeiten die w\u00e4hrend der vorherigen Sitzung zwischengespeicherten Daten verwenden. Wir mussten nur die Typpr\u00fcfungen in den ge\u00e4nderten Dateien und in den Dateien durchf\u00fchren, die von ihnen abhingen. Mypy ging sogar noch einen Schritt weiter: Wenn sich die \u00e4u\u00dfere Schnittstelle des Moduls nicht ge\u00e4ndert hat, ging mypy davon aus, dass andere Module, die dieses Modul importieren, nicht erneut gepr\u00fcft werden m\u00fcssen.<\/p>\n<p>Die inkrementelle \u00dcberpr\u00fcfung hat uns erheblich bei der Annotation gro\u00dfer Codebasen geholfen. Der Grund daf\u00fcr ist, dass dieser Prozess normalerweise viele iterative Ausf\u00fchrungen von mypy umfasst, da Annotationen schrittweise zum Code hinzugef\u00fcgt und kontinuierlich verbessert werden. Der erste mypy-Durchlauf war immer noch sehr langsam, da viele Abh\u00e4ngigkeiten \u00fcberpr\u00fcft werden mussten. Um die Situation zu verbessern, haben wir einen Mechanismus zur Remote-Caching implementiert. Wenn mypy erkennt, dass der lokale Cache wahrscheinlich veraltet ist, l\u00e4dt es den aktuellen Snapshot des Caches f\u00fcr die gesamte Codebasis aus einem zentralen Repository. Anschlie\u00dfend f\u00fchrt es mit diesem Snapshot eine inkrementelle \u00dcberpr\u00fcfung durch. Dies hat uns einen weiteren erheblichen Schritt in Richtung Leistungssteigerung von mypy gebracht.<\/p>\n<p>Dies war eine Phase der schnellen und nat\u00fcrlichen Einf\u00fchrung des Typsystems bei Dropbox. Bis Ende 2016 hatten wir bereits etwa 420.000 Zeilen Python-Code mit Typannotationen. Viele Benutzer begr\u00fc\u00dften die Typ\u00fcberpr\u00fcfung enthusiastisch. In Dropbox wurde mypy von immer mehr Entwicklerteams genutzt.<\/p>\n<p>Alles sah anfangs gut aus, aber es gab noch viel zu tun. Wir begannen mit regelm\u00e4\u00dfigen internen Befragungen der Nutzer, um Probleme im Projekt zu identifizieren und herauszufinden, welche Fragen priorit\u00e4r zu l\u00f6sen waren (diese Praxis wird bis heute im Unternehmen angewendet). Es wurde klar, dass zwei Aufgaben besonders wichtig waren. Erstens ben\u00f6tigten wir eine bessere Codeabdeckung durch Typen, und zweitens musste mypy schneller arbeiten. Es war offensichtlich, dass unsere Bem\u00fchungen, mypy zu beschleunigen und es in die Projekte des Unternehmens zu integrieren, noch lange nicht abgeschlossen waren. In vollem Bewusstsein der Bedeutung dieser beiden Aufgaben machten wir uns an ihre L\u00f6sung.<\/p>\n<h2>Mehr Leistung!<\/h2>\n<p>\nInkrementelle Pr\u00fcfungen haben mypy beschleunigt, aber das Werkzeug war dennoch nicht schnell genug. Viele inkrementelle Pr\u00fcfungen dauerten etwa eine Minute. Der Grund daf\u00fcr waren zyklische Importe. Das d\u00fcrfte niemanden \u00fcberraschen, der schon einmal mit gro\u00dfen Codebasen in Python gearbeitet hat. Wir hatten Sets aus hunderten von Modulen, die alle anderen indirekt importierten. Wenn eine Datei in einem Importzyklus ver\u00e4ndert wurde, musste mypy alle Dateien in diesem Zyklus verarbeiten und oft auch alle Module, die Module aus diesem Zyklus importierten. Einer dieser Zyklen war der ber\u00fcchtigte \"Abh\u00e4ngigkeitskn\u00e4uel\", der bei Dropbox f\u00fcr viele Probleme sorgte. Einmal enthielt diese Struktur mehrere hundert Module, die von zahlreichen Tests direkt oder indirekt importiert wurden und auch im Produktionscode verwendet wurden.<\/p>\n<p>Wir haben die M\u00f6glichkeit in Betracht gezogen, zyklische Abh\u00e4ngigkeiten aufzul\u00f6sen, aber uns fehlen die Ressourcen daf\u00fcr. Es gab zu viel Code, mit dem wir nicht vertraut waren. Letztlich haben wir einen alternativen Ansatz gew\u00e4hlt. Wir entschieden uns daf\u00fcr, mypy so zu gestalten, dass es auch bei \u201averwickelten Abh\u00e4ngigkeiten\u2018 schnell arbeitet. Dieses Ziel haben wir mit einem mypy-Daemon erreicht. Der Daemon ist ein Serverprozess, der zwei interessante Funktionen implementiert. Erstens speichert er Informationen \u00fcber die gesamte Codebasis im Arbeitsspeicher. Das bedeutet, dass beim Start von mypy keine zwischengespeicherten Daten zu Tausenden von importierten Abh\u00e4ngigkeiten geladen werden m\u00fcssen. Zweitens analysiert er sorgf\u00e4ltig, auf einer feinen strukturellen Ebene, die Abh\u00e4ngigkeiten zwischen Funktionen und anderen Entit\u00e4ten. Zum Beispiel, wenn eine Funktion <code>foo<\/code> eine Funktion aufruft <code>bar<\/code>, dann besteht eine Abh\u00e4ngigkeit <code>foo<\/code> ab <code>bar<\/code>. Wenn sich eine Datei \u00e4ndert, verarbeitet der Daemon zun\u00e4chst isoliert nur die ge\u00e4nderte Datei. Anschlie\u00dfend betrachtet er die f\u00fcr au\u00dfen Sichtbaren Ver\u00e4nderungen dieser Datei, wie etwa ge\u00e4nderte Funktionssignaturen. Der Daemon verwendet detaillierte Informationen zu den Importen nur zur \u00dcberpr\u00fcfung der Funktionen, die tats\u00e4chlich die ge\u00e4nderte Funktion verwenden. In der Regel m\u00fcssen dabei nur wenige Funktionen \u00fcberpr\u00fcft werden.<\/p>\n<p>Die Umsetzung all dessen war eine anspruchsvolle Aufgabe, da die urspr\u00fcngliche Implementierung von mypy stark auf die Verarbeitung einer Datei zur Zeit ausgerichtet war. Wir mussten uns mit zahlreichen Grenzf\u00e4llen auseinandersetzen, die erneute \u00dcberpr\u00fcfungen erforderten, wenn sich etwas im Code \u00e4nderte. Beispielsweise geschieht dies, wenn einer Klasse eine neue Basisklasse zugewiesen wird. Nachdem wir das, was wir wollten, umgesetzt hatten, konnten wir die Ausf\u00fchrungszeit der meisten inkrementellen Pr\u00fcfungen auf nur wenige Sekunden reduzieren. Das schien uns ein gro\u00dfer Erfolg zu sein.<\/p>\n<h2>Noch mehr Leistung!<\/h2>\n<p>\nZusammen mit dem bereits erw\u00e4hnten Remote-Caching hat mypy praktisch alle Probleme gel\u00f6st, die beim h\u00e4ufigen Ausf\u00fchren der Typ\u00fcberpr\u00fcfung durch Programmierer auftreten, wenn nur wenige Dateien ge\u00e4ndert werden. Dennoch blieb die Systemleistung in der ung\u00fcnstigsten Nutzungssituation nach wie vor suboptimal. Ein reiner mypy-Durchlauf konnte \u00fcber 15 Minuten in Anspruch nehmen. Das war weit mehr, als wir uns gew\u00fcnscht h\u00e4tten. Jede Woche verschlechterte sich die Situation weiter, da die Programmierer weiterhin neuen Code schrieben und Annotationen zu bestehendem Code hinzuf\u00fcgten. Unsere Benutzer verlangten nach mehr Leistung, und wir waren gerne bereit, ihren Bed\u00fcrfnissen nachzukommen.<\/p>\n<p>Wir haben uns entschieden, zu einer der fr\u00fchen Ideen von mypy zur\u00fcckzukehren. N\u00e4mlich zur Umwandlung von Python-Code in C-Code. Experimente mit Cython (einer Plattform, die es erm\u00f6glicht, in Python geschriebenen Code in C-Code zu \u00fcbersetzen) haben uns kein sichtbares Beschleunigungsresultat gebracht, also beschlossen wir, die Idee zu erneuern, einen eigenen Compiler zu entwickeln. Da der mypy-Code (in Python geschrieben) bereits alle notwendigen Typannotationen enthielt, schien es uns sinnvoll, diese Annotationsm\u00f6glichkeiten zu nutzen, um die Systemleistung zu optimieren. Ich habe schnell einen Prototyp zur \u00dcberpr\u00fcfung dieser Idee erstellt. Dieser zeigte bei verschiedenen Mikro-Benchmarks ein \u00fcber zehnmal besseres Leistungswachstum. Unsere Idee war es, Python-Module mit Cython in C-Module zu kompilieren und die Typannotationen in Typpr\u00fcfungen umzuwandeln, die zur Laufzeit des Programms durchgef\u00fchrt werden (normalerweise werden Typannotationen w\u00e4hrend der Programmausf\u00fchrung ignoriert und nur von Typpr\u00fcfungs-Systemen verwendet). Wir planten tats\u00e4chlich, die mypy-Implementierung von Python in eine statisch typisierte Sprache zu \u00fcbertragen, die genau so aussehen sollte (und gr\u00f6\u00dftenteils wie Python funktionieren sollte). (Diese Form der intersprachlichen Migration wurde zu einer Art Tradition des mypy-Projekts. Die urspr\u00fcngliche Implementierung von mypy wurde in Alore geschrieben, gefolgt von einer syntaktischen Hybridversion von Java und Python.)<\/p>\n<p>Die Fokussierung auf die API-Erweiterungen von CPython war entscheidend, um die Projektmanagementf\u00e4higkeiten nicht zu verlieren. Es war nicht notwendig, eine virtuelle Maschine oder spezielle Bibliotheken f\u00fcr mypy zu implementieren. Zudem blieb uns die gesamte Python-\u00d6kosystem zug\u00e4nglich, einschlie\u00dflich aller Werkzeuge wie pytest. Das bedeutete, dass wir weiterhin interpretierten Python-Code w\u00e4hrend der Entwicklung nutzen konnten, was uns erm\u00f6glichte, mit einem sehr schnellen Schema zur Code\u00e4nderung und -tests fortzufahren, anstatt auf die Kompilierung des Codes zu warten. Es f\u00fchlte sich an, als ob wir es erfolgreich schafften, sozusagen auf zwei Hochzeiten gleichzeitig zu tanzen, und das gefiel uns.<\/p>\n<p>Der Compiler, den wir mypyc genannt haben (da er als Frontend mypy zur Typanalyse verwendet), hat sich als sehr erfolgreiches Projekt erwiesen. Insgesamt haben wir eine etwa vierfache Beschleunigung der h\u00e4ufigen Ausf\u00fchrungen von mypy ohne den Einsatz von Caching erreicht. Die Entwicklung des Kernprojekts mypyc nahm bei unserem kleinen Team, zu dem Michael Sullivan, Ivan Levkivskyi, Hugh Han und ich geh\u00f6rten, etwa 4 Kalendermonate in Anspruch. Dieser Aufwand war deutlich geringer als der, der n\u00f6tig gewesen w\u00e4re, um mypy beispielsweise in C++ oder Go neu zu schreiben. Auch die notwendigen \u00c4nderungen im Projekt waren weitaus weniger umfangreich, als sie bei einer Neuprogrammierung in einer anderen Sprache gewesen w\u00e4ren. Dar\u00fcber hinaus hatten wir die Hoffnung, dass wir mypyc so weit bringen k\u00f6nnten, dass auch andere Programmierer von Dropbox es zur Kompilierung und Beschleunigung ihres Codes nutzen k\u00f6nnen.<\/p>\n<p>Um ein solches Leistungsniveau zu erreichen, mussten wir einige interessante ingenieurtechnische L\u00f6sungen anwenden. So kann der Compiler die Ausf\u00fchrung vieler Operationen durch die Nutzung schneller, grundlegender C-Konstrukte beschleunigen. Zum Beispiel wird der Aufruf einer kompilierten Funktion in einen C-Funktionsaufruf \u00fcbersetzt. Ein solcher Aufruf erfolgt viel schneller als der einer interpretierten Funktion. Einige Operationen, wie z. B. die Suche in Dictionaries, basierten jedoch immer noch auf herk\u00f6mmlichen Aufrufen der C-API aus CPython, die nach der Kompilierung nur wenig schneller waren. Wir konnten die zus\u00e4tzliche Belastung des Systems, die durch die Interpretation verursacht wurde, beseitigen, aber dies brachte nur einen geringen Performance-Gewinn.<\/p>\n<p>Um die h\u00e4ufigsten \"langsamen\" Operationen zu identifizieren, haben wir eine Code-Profilierung durchgef\u00fchrt. Mit den gewonnenen Daten haben wir versucht, entweder mypyc so zu optimieren, dass es effizienteren C-Code f\u00fcr diese Operationen generiert, oder den entsprechenden Python-Code mit schnelleren Operationen neu zu schreiben (manchmal hatten wir einfach nicht die M\u00f6glichkeit, eine einfache L\u00f6sung f\u00fcr ein bestimmtes Problem zu finden). Das \u00dcberarbeiten des Python-Codes stellte sich oft als einfachere L\u00f6sung heraus, als die automatische Umsetzung derselben Transformationen im Compiler zu realisieren. Langfristig strebten wir an, viele dieser Transformationen zu automatisieren, doch in diesem Moment wollten wir mypy mit minimalem Aufwand beschleunigen. Auf dem Weg zu diesem Ziel haben wir einige Abk\u00fcrzungen genommen.<\/p>\n<p>Die Fortsetzung folgt\u2026<\/p>\n<p><b>Sehr geehrte Leser!<\/b> Welche Eindr\u00fccke hatte das mypy-Projekt, als Sie von seiner Existenz erfuhren?<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/vps_start\/\"><img decoding=\"async\" alt=\"Der Weg zur \u00dcberpr\u00fcfung von 4 Millionen Zeilen Python-Code. Teil 2\" src=\"\/wp-content\/uploads\/2019\/09\/e3c1dd40228b56d0196fd65e4df22a59.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/ru-rub\/#order\"><img decoding=\"async\" alt=\"Der Weg zur \u00dcberpr\u00fcfung von 4 Millionen Zeilen Python-Code. Teil 2\" src=\"\/wp-content\/uploads\/2019\/09\/263173dd3ab487da330ff9063e3c180e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<br \/>Quelle: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u2192 \u0427\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 (PEP 484) \u041c\u044b \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b \u0441 mypy \u0432 Dropbox \u0432\u043e \u0432\u0440\u0435\u043c\u044f Hack Week 2014. Hack Week \u2014 \u044d\u0442\u043e \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u0435, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c\u043e\u0435 Dropbox \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u043d\u0435\u0434\u0435\u043b\u0438. \u0412 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28879,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38479","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 4.9.10 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u2192 \u0427\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 (PEP 484) \u041c\u044b \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b \u0441 mypy \u0432 Dropbox \u0432\u043e \u0432\u0440\u0435\u043c\u044f Hack Week 2014. Hack Week \u2014 \u044d\u0442\u043e \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u0435, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c\u043e\u0435 Dropbox \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u043d\u0435\u0434\u0435\u043b\u0438. \u0412 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 4.9.10\" \/>\n\t\t<meta property=\"og:locale\" content=\"de_DE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u0443\u0442\u044c \u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0442\u0438\u043f\u043e\u0432 4 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u0427\u0430\u0441\u0442\u044c 2 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u2192 \u0427\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 (PEP 484) \u041c\u044b \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b \u0441 mypy \u0432 Dropbox \u0432\u043e \u0432\u0440\u0435\u043c\u044f Hack Week 2014. Hack Week \u2014 \u044d\u0442\u043e \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u0435, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c\u043e\u0435 Dropbox \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u043d\u0435\u0434\u0435\u043b\u0438. \u0412 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:23:56+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:23:56+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Der Weg zur Typpr\u00fcfung von 4 Millionen Zeilen Python-Code. Teil 2 | ProHoster","description":"Heute ver\u00f6ffentlichen wir den zweiten Teil der \u00dcbersetzung des Materials dar\u00fcber, wie Dropbox die Typ\u00fcberpr\u00fcfung von mehreren Millionen Zeilen Python-Code organisiert hat. \u2192 Lesen Sie den ersten Teil. Offizielle Unterst\u00fctzung f\u00fcr Typen (PEP 484) Wir haben w\u00e4hrend der Hack Week 2014 in Dropbox erste ernsthafte Experimente mit mypy durchgef\u00fchrt. Die Hack Week ist eine Veranstaltung, die Dropbox eine Woche lang veranstaltet. In dieser Zeit","canonical_url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"de_DE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u0443\u0442\u044c \u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0435 \u0442\u0438\u043f\u043e\u0432 4 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u0427\u0430\u0441\u0442\u044c 2 | ProHoster","og:description":"\u0421\u0435\u0433\u043e\u0434\u043d\u044f \u043f\u0443\u0431\u043b\u0438\u043a\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u0432 Dropbox \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u044b\u0432\u0430\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044c \u0442\u0438\u043f\u043e\u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a Python-\u043a\u043e\u0434\u0430. \u2192 \u0427\u0438\u0442\u0430\u0442\u044c \u043f\u0435\u0440\u0432\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 (PEP 484) \u041c\u044b \u043f\u0440\u043e\u0432\u0435\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 \u0441\u0435\u0440\u044c\u0451\u0437\u043d\u044b\u0435 \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u044b \u0441 mypy \u0432 Dropbox \u0432\u043e \u0432\u0440\u0435\u043c\u044f Hack Week 2014. Hack Week \u2014 \u044d\u0442\u043e \u043c\u0435\u0440\u043e\u043f\u0440\u0438\u044f\u0442\u0438\u0435, \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043c\u043e\u0435 Dropbox \u0432 \u0442\u0435\u0447\u0435\u043d\u0438\u0435 \u043e\u0434\u043d\u043e\u0439 \u043d\u0435\u0434\u0435\u043b\u0438. \u0412 \u044d\u0442\u043e \u0432\u0440\u0435\u043c\u044f","og:url":"https:\/\/prohoster.info\/de\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:23:56+00:00","article:modified_time":"2019-10-31T19:23:56+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38479","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 22:13:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:08:32","updated":"2026-01-23 22:13:19"},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/38479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/comments?post=38479"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/posts\/38479\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media\/28879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/media?parent=38479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/categories?post=38479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/de\/wp-json\/wp\/v2\/tags?post=38479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}