{"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\/pl\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2","title":{"rendered":"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w linii kodu Python. Cz\u0119\u015b\u0107 2","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Dzi\u015b publikujemy drug\u0105 cz\u0119\u015b\u0107 t\u0142umaczenia materia\u0142u o tym, jak w Dropboxie zorganizowano kontrol\u0119 typ\u00f3w kilku milion\u00f3w linii kodu Python.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\"><img decoding=\"async\" alt=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w linii kodu Python. Cz\u0119\u015b\u0107 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\/\">Przeczytaj pierwsz\u0105 cz\u0119\u015b\u0107<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Oficjalne wsparcie dla typ\u00f3w (PEP 484)<\/h2>\n<p>\nPrzeprowadzili\u015bmy nasze pierwsze powa\u017cne eksperymenty z mypy w Dropboxie podczas Hack Week 2014. Hack Week to wydarzenie organizowane przez Dropbox przez tydzie\u0144, w tym czasie pracownicy mog\u0105 zajmowa\u0107 si\u0119 czymkolwiek! Niekt\u00f3re z najs\u0142ynniejszych projekt\u00f3w technologicznych Dropboxa zacz\u0119\u0142y si\u0119 w\u0142a\u015bnie podczas takich wydarze\u0144. W wyniku tego eksperymentu doszli\u015bmy do wniosku, \u017ce mypy wygl\u0105da obiecuj\u0105co, chocia\u017c projekt ten nadal nie by\u0142 gotowy do szerokiego u\u017cytku.<\/p>\n<p>Wtedy w powietrzu unosi\u0142a si\u0119 idea standaryzacji system\u00f3w wydawania wskaz\u00f3wek dotycz\u0105cych typ\u00f3w Python. Jak ju\u017c m\u00f3wi\u0142em, od wersji Python 3.0 mo\u017cna by\u0142o korzysta\u0107 z adnotacji typ\u00f3w w funkcjach, ale by\u0142y to jedynie dowolne wyra\u017cenia, bez okre\u015blonej sk\u0142adni i semantyki. W trakcie wykonywania programu te adnotacje w du\u017cej mierze by\u0142y po prostu ignorowane. Po Hack Week zacz\u0119li\u015bmy pracowa\u0107 nad standaryzacj\u0105 semantyki. Prace te doprowadzi\u0142y do powstania <noindex><a rel=\"nofollow\" href=\"https:\/\/www.python.org\/dev\/peps\/pep-0484\/\">PEP 484<\/a><\/noindex> (ten dokument by\u0142 wsp\u00f3\u0142tworzony przez Guido van Rossuma, \u0141ukasza Langa i mnie).<\/p>\n<p>Nasze motywy mo\u017cna by\u0142o rozpatrywa\u0107 z dw\u00f3ch stron. Po pierwsze, mieli\u015bmy nadziej\u0119, \u017ce ca\u0142e ekosystem Python mog\u0142oby przyj\u0105\u0107 wsp\u00f3lne podej\u015bcie do korzystania z sugestii dotycz\u0105cych typ\u00f3w (type hints \u2014 termin u\u017cywany w Pythonie jako odpowiednik \u201eadnotacji typ\u00f3w\u201d). Bior\u0105c pod uwag\u0119 mo\u017cliwe ryzyko, by\u0142oby to lepsze ni\u017c korzystanie z wielu wzajemnie niekompatybilnych podej\u015b\u0107. Po drugie, chcieli\u015bmy otwarcie om\u00f3wi\u0107 mechanizmy adnotowania typ\u00f3w z wieloma przedstawicielami spo\u0142eczno\u015bci Python. Cz\u0119\u015bciowo to pragnienie wynika\u0142o z tego, \u017ce nie chcieli\u015bmy wygl\u0105da\u0107 jak \u201eodst\u0119pcy\u201d od podstawowych idei j\u0119zyka w oczach szerszych rzeszy programist\u00f3w Python. Jest to j\u0119zyk o dynamicznej typizacji, znany z \u201etypizacji kaczki\u201d. Na pocz\u0105tku w spo\u0142eczno\u015bci mog\u0142o pojawi\u0107 si\u0119 kilka podejrzliwych reakcji na pomys\u0142 statycznej typizacji. Ale takie nastawienie ostatecznie os\u0142ab\u0142o \u2014 po tym, jak sta\u0142o si\u0119 jasne, \u017ce statyczna typizacja nie ma by\u0107 obowi\u0105zkowa (i po tym, jak ludzie zrozumieli, \u017ce jest naprawd\u0119 u\u017cyteczna).<\/p>\n<p>Ostatecznie przyj\u0119ta sk\u0142adnia podpowiedzi typ\u00f3w by\u0142a bardzo podobna do tej, kt\u00f3r\u0105 w\u00f3wczas obs\u0142ugiwa\u0142 mypy. Dokument PEP 484 zosta\u0142 wydany wraz z Pythonem 3.5 w 2015 roku. Python przesta\u0142 by\u0107 j\u0119zykiem, kt\u00f3ry obs\u0142ugiwa\u0142 wy\u0142\u0105cznie dynamiczne typowanie. Lubi\u0119 my\u015ble\u0107 o tym wydarzeniu jako o znacz\u0105cej cezurze w historii Pythona.<\/p>\n<h2>Pocz\u0105tek migracji<\/h2>\n<p>\nPod koniec 2015 roku w Dropbox stworzyli\u015bmy zesp\u00f3\u0142 z\u0142o\u017cony z trzech os\u00f3b, aby pracowa\u0107 nad mypy. W jego sk\u0142ad weszli Guido van Rossum, Greg Price i David Fisher. Od tego momentu sytuacja zacz\u0119\u0142a szybko si\u0119 rozwija\u0107. Pierwsz\u0105 przeszkod\u0105 na drodze wzrostu mypy by\u0142a wydajno\u015b\u0107. Jak ju\u017c wspomnia\u0142em powy\u017cej, na wczesnym etapie rozwoju projektu zastanawia\u0142em si\u0119 nad przet\u0142umaczeniem implementacji mypy na j\u0119zyk C, ale ten pomys\u0142 zosta\u0142 na razie skre\u015blony z listy. Utkn\u0119li\u015bmy przy tym, \u017ce do uruchomienia systemu u\u017cywany by\u0142 interpreter CPython, kt\u00f3ry nie charakteryzowa\u0142 si\u0119 wystarczaj\u0105c\u0105 szybko\u015bci\u0105 dla narz\u0119dzi takich jak mypy. (Projekt PyPy, alternatywna implementacja Pythona z kompilatorem JIT, r\u00f3wnie\u017c nam nie pom\u00f3g\u0142.)<\/p>\n<p>Na szcz\u0119\u015bcie przysz\u0142y z pomoc\u0105 pewne algorytmiczne usprawnienia. Pierwszym pot\u0119\u017cnym \"przyspieszaczem\" by\u0142a implementacja inkrementalnej kontroli. Pomys\u0142 tego usprawnienia by\u0142 prosty: je\u015bli wszystkie zale\u017cno\u015bci modu\u0142u od ostatniego uruchomienia mypy si\u0119 nie zmieni\u0142y, mo\u017cemy skorzysta\u0107 podczas pracy z zale\u017cno\u015bciami z danych, kt\u00f3re zosta\u0142y zbuforowane podczas poprzedniej sesji. Musieli\u015bmy tylko przeprowadzi\u0107 kontrol\u0119 typ\u00f3w w zmienionych plikach oraz tych plikach, kt\u00f3re by\u0142y od nich zale\u017cne. Mypy posz\u0142o nawet nieco dalej: je\u015bli zewn\u0119trzny interfejs modu\u0142u si\u0119 nie zmieni\u0142 \u2014 mypy uznawa\u0142o, \u017ce inne modu\u0142y importuj\u0105ce ten modu\u0142 nie musz\u0105 by\u0107 ponownie sprawdzane.<\/p>\n<p>Inkrementalne sprawdzanie bardzo pomog\u0142o nam podczas annotacji du\u017cych zbior\u00f3w istniej\u0105cego kodu. Chodzi o to, \u017ce ten proces zazwyczaj obejmuje wiele iteracyjnych uruchomie\u0144 mypy, poniewa\u017c adnotacje s\u0105 stopniowo dodawane do kodu i stopniowo poprawiane. Pierwsze uruchomienie mypy wci\u0105\u017c by\u0142o bardzo wolne, poniewa\u017c podczas jego wykonania nale\u017ca\u0142o sprawdzi\u0107 wiele zale\u017cno\u015bci. W celu poprawy sytuacji wdro\u017cyli\u015bmy mechanizm zdalnego buforowania. Je\u015bli mypy stwierdzi, \u017ce lokalny bufor prawdopodobnie jest nieaktualny, pobiera aktualny zrzut bufora dla ca\u0142ej bazy kodu z centralnego repozytorium. Nast\u0119pnie wykonuje, korzystaj\u0105c z tej kopii, inkrementalne sprawdzanie. To jeszcze o jeden znacz\u0105cy krok przyspieszy\u0142o nas na drodze do zwi\u0119kszenia wydajno\u015bci mypy.<\/p>\n<p>To by\u0142 okres szybkiej i naturalnej implementacji systemu sprawdzania typ\u00f3w w Dropbox. Pod koniec 2016 roku mieli\u015bmy ju\u017c oko\u0142o 420000 linii kodu Python z adnotacjami typ\u00f3w. Wiele os\u00f3b entuzjastycznie podchodzi\u0142o do sprawdzania typ\u00f3w. W Dropbox mypy by\u0142o wykorzystywane przez coraz wi\u0119ksze zespo\u0142y programistyczne.<\/p>\n<p>Wszystko wtedy wygl\u0105da\u0142o dobrze, ale mieli\u015bmy jeszcze wiele do zrobienia. Zacz\u0119li\u015bmy przeprowadza\u0107 okresowe wewn\u0119trzne ankiety w\u015br\u00f3d u\u017cytkownik\u00f3w, aby zidentyfikowa\u0107 problemy projektu i zrozumie\u0107, jakie pytania nale\u017cy rozwi\u0105za\u0107 w pierwszej kolejno\u015bci (ta praktyka jest stosowana w firmie nawet do dzi\u015b). Jak si\u0119 okaza\u0142o, najwa\u017cniejsze by\u0142y dwa zadania. Po pierwsze, potrzebne by\u0142o wi\u0119ksze pokrycie kodu typami, po drugie, mypy mia\u0142o dzia\u0142a\u0107 szybciej. By\u0142o zupe\u0142nie jasne, \u017ce nasza praca nad przyspieszeniem mypy i jego wdro\u017ceniem w projektach firmy by\u0142a wci\u0105\u017c daleka od zako\u0144czenia. W pe\u0142ni zdaj\u0105c sobie spraw\u0119 z wagi tych dw\u00f3ch zada\u0144, zabra\u0142y si\u0119 za ich rozwi\u0105zanie.<\/p>\n<h2>Wi\u0119cej wydajno\u015bci!<\/h2>\n<p>\nSprawdzanie inkrementalne przyspieszy\u0142o mypy, ale ten narz\u0119dzie wci\u0105\u017c nie by\u0142o wystarczaj\u0105co szybkie. Wiele sprawdze\u0144 inkrementalnych trwa\u0142o oko\u0142o minuty. Przyczyn\u0105 tego by\u0142y importy cykliczne. To prawdopodobnie nie zdziwi nikogo, kto pracowa\u0142 z du\u017cymi bazami kodu napisanymi w Pythonie. Mieli\u015bmy zestawy z setkami modu\u0142\u00f3w, z kt\u00f3rych ka\u017cdy po\u015brednio importowa\u0142 wszystkie pozosta\u0142e. Je\u015bli jakikolwiek plik w cyklu import\u00f3w by\u0142 zmieniony, mypy musia\u0142 przetworzy\u0107 wszystkie pliki wchodz\u0105ce w ten cykl, a cz\u0119sto tak\u017ce jakiekolwiek modu\u0142y, kt\u00f3re importowa\u0142y modu\u0142y z tego cyklu. Jednym z takich cykli by\u0142o g\u0142o\u015bno krytykowane \"k\u0142\u0119bek zale\u017cno\u015bci\", kt\u00f3re przysporzy\u0142o wielu k\u0142opot\u00f3w w Dropboxie. Kiedy\u015b ta struktura zawiera\u0142a w sobie kilka setek modu\u0142\u00f3w, kt\u00f3re by\u0142y importowane, bezpo\u015brednio lub po\u015brednio, przez wiele test\u00f3w, a tak\u017ce wykorzystywane w kodzie produkcyjnym.<\/p>\n<p>Rozwa\u017cali\u015bmy mo\u017cliwo\u015b\u0107 \"rozwik\u0142ania\" cyklicznych zale\u017cno\u015bci, ale nie mieli\u015bmy zasob\u00f3w, aby to zrobi\u0107. By\u0142o tam za du\u017co kodu, z kt\u00f3rym nie byli\u015bmy zaznajomieni. W ko\u0144cu poszli\u015bmy w alternatywnym kierunku. Postanowili\u015bmy sprawi\u0107, aby mypy dzia\u0142a\u0142 szybko nawet w obecno\u015bci \"k\u0142\u0119bk\u00f3w zale\u017cno\u015bci\". Osi\u0105gn\u0119li\u015bmy ten cel dzi\u0119ki demonowi mypy. Demon to proces serwera, kt\u00f3ry realizuje dwie interesuj\u0105ce mo\u017cliwo\u015bci. Po pierwsze - przechowuje w pami\u0119ci informacje o ca\u0142ej bazie kodu. Oznacza to, \u017ce przy ka\u017cdym uruchomieniu mypy nie trzeba za\u0142adowa\u0107 pami\u0119ci podr\u0119cznej dotycz\u0105cej tysi\u0119cy importowanych zale\u017cno\u015bci. Po drugie - szczeg\u00f3\u0142owo analizuje zale\u017cno\u015bci mi\u0119dzy funkcjami i innymi bytami na poziomie ma\u0142ych struktur. Na przyk\u0142ad, je\u015bli funkcja <code>foo<\/code> wywo\u0142uje funkcj\u0119 <code>bar<\/code>, to istnieje zale\u017cno\u015b\u0107 <code>foo<\/code> od <code>bar<\/code>. Kiedy plik si\u0119 zmienia - demon najpierw, w izolacji, przetwarza tylko zmieniony plik. Nast\u0119pnie przygl\u0105da si\u0119 zmianom w tym pliku, widocznym na zewn\u0105trz, takim jak zmienione sygnatury funkcji. Demon wykorzystuje szczeg\u00f3\u0142owe informacje o importach tylko do ponownego sprawdzenia tych funkcji, kt\u00f3re naprawd\u0119 u\u017cywaj\u0105 zmienionej funkcji. Zazwyczaj przy takim podej\u015bciu trzeba sprawdza\u0107 tylko niewielk\u0105 liczb\u0119 funkcji.<\/p>\n<p>Wdro\u017cenie tego wszystkiego by\u0142o trudnym zadaniem, poniewa\u017c pocz\u0105tkowa implementacja mypy by\u0142a mocno skierowana na przetwarzanie jednego pliku naraz. Musieli\u015bmy zmierzy\u0107 si\u0119 z wieloma sytuacjami granicznymi, kt\u00f3rych wyst\u0105pienie wymaga\u0142o ponownych weryfikacji, gdy w kodzie co\u015b si\u0119 zmienia\u0142o. Na przyk\u0142ad, dzieje si\u0119 tak, gdy klasie przypisywana jest nowa klasa bazowa. Po tym, jak zrealizowali\u015bmy to, co chcieli\u015bmy, zdo\u0142ali\u015bmy skr\u00f3ci\u0107 czas wykonywania wi\u0119kszo\u015bci inkrementalnych kontroli do kilku sekund. Uwa\u017cali\u015bmy to za du\u017cy sukces.<\/p>\n<h2>Jeszcze wi\u0119cej wydajno\u015bci!<\/h2>\n<p>\nRazem z zdalnym buforowaniem, o kt\u00f3rym m\u00f3wi\u0142em wcze\u015bniej, demon mypy prawie ca\u0142kowicie rozwi\u0105za\u0142 problemy, kt\u00f3re pojawia\u0142y si\u0119, gdy programista cz\u0119sto uruchamia kontrol\u0119 typ\u00f3w, wprowadzaj\u0105c zmiany w niewielkiej liczbie plik\u00f3w. Niemniej jednak wydajno\u015b\u0107 systemu w najmniej sprzyjaj\u0105cych warunkach u\u017cytkowania by\u0142a wci\u0105\u017c daleka od optymalnej. Czyste uruchomienie mypy mog\u0142o zaj\u0105\u0107 ponad 15 minut. A to by\u0142o znacznie wi\u0119cej, ni\u017c by nas satysfakcjonowa\u0142o. Sytuacja co tydzie\u0144 stawa\u0142a si\u0119 coraz gorsza, poniewa\u017c programi\u015bci nadal pisali nowy kod i dodawali adnotacje do istniej\u0105cego kodu. Nasi u\u017cytkownicy wci\u0105\u017c pragn\u0119li wi\u0119kszej wydajno\u015bci, a my ch\u0119tnie starali\u015bmy si\u0119 im w tym pom\u00f3c.<\/p>\n<p>Postanowili\u015bmy wr\u00f3ci\u0107 do jednego z wcze\u015bniejszych pomys\u0142\u00f3w dotycz\u0105cych mypy. A mianowicie \u2014 do przekszta\u0142cania kodu Pythona w kod C. Eksperymenty z Cythonem (systemem, kt\u00f3ry umo\u017cliwia t\u0142umaczenie kodu napisanego w Pythonie na kod C) nie przynios\u0142y widocznego przyspieszenia, wi\u0119c postanowili\u015bmy wskrzesi\u0107 pomys\u0142 stworzenia w\u0142asnego kompilatora. Poniewa\u017c baza kodu mypy (napisana w Pythonie) ju\u017c zawiera\u0142a wszystkie niezb\u0119dne adnotacje typ\u00f3w, wydawa\u0142o si\u0119 to wart\u0105 pr\u00f3b\u0105 wykorzystania tych adnotacji do zwi\u0119kszenia wydajno\u015bci systemu. Szybko stworzy\u0142em prototyp w celu przetestowania tego pomys\u0142u. Wykaza\u0142 on na r\u00f3\u017cnych mikro-benchmarkach ponad 10-krotne zwi\u0119kszenie wydajno\u015bci. Naszym pomys\u0142em by\u0142o kompilowanie modu\u0142\u00f3w Pythona do modu\u0142\u00f3w C za pomoc\u0105 Cythona oraz przekszta\u0142canie adnotacji typ\u00f3w w kontrole typ\u00f3w wykonywane w czasie dzia\u0142ania programu (zwykle adnotacje typ\u00f3w s\u0105 ignorowane podczas wykonywania program\u00f3w i u\u017cywane tylko przez systemy do sprawdzania typ\u00f3w). W rzeczywisto\u015bci planowali\u015bmy przet\u0142umaczy\u0107 implementacj\u0119 mypy z Pythona na j\u0119zyk, kt\u00f3ry by\u0142by stworzony statycznie typowany i wygl\u0105da\u0142 (a w wi\u0119kszo\u015bci przypadk\u00f3w dzia\u0142a\u0142) dok\u0142adnie tak, jak Python. (Ten rodzaj mi\u0119dzyj\u0119zykowej migracji sta\u0142 si\u0119 czym\u015b w rodzaju tradycji projektu mypy. Pierwsza implementacja mypy zosta\u0142a napisana w Alore, potem by\u0142 to hybrydowy sk\u0142adnia Javy i Pythona).<\/p>\n<p>Ukierunkowanie na API rozszerze\u0144 CPython by\u0142o kluczem do zachowania mo\u017cliwo\u015bci zarz\u0105dzania projektem. Nie musieli\u015bmy implementowa\u0107 maszyny wirtualnej ani jakichkolwiek bibliotek, z kt\u00f3rych korzysta\u0142 mypy. Ponadto wci\u0105\u017c mieliby\u015bmy dost\u0119p do ca\u0142ego ekosystemu Pythona, wszystkie narz\u0119dzia (takie jak pytest) by\u0142yby dost\u0119pne. Oznacza\u0142o to, \u017ce mogliby\u015bmy kontynuowa\u0107 korzystanie z interpretowanego kodu Pythona w trakcie rozwoju, co pozwoli\u0142oby nam na dalsz\u0105 prac\u0119, korzystaj\u0105c z bardzo szybkiego schematu wprowadzania poprawek do kodu i jego testowania, zamiast czeka\u0107 na kompilacj\u0119 kodu. Wygl\u0105da\u0142o to tak, jakby\u015bmy \u015bwietnie sobie radzili, mo\u017cna powiedzie\u0107, \u017ce siedzimy na dw\u00f3ch krzes\u0142ach, i nam si\u0119 to podoba\u0142o.<\/p>\n<p>Kompilator, kt\u00f3ry nazwali\u015bmy mypyc (poniewa\u017c wykorzystuje mypy do analizy typ\u00f3w jako frontend), okaza\u0142 si\u0119 bardzo udanym projektem. Og\u00f3lnie rzecz bior\u0105c, osi\u0105gn\u0119li\u015bmy oko\u0142o czterokrotnego przyspieszenia w przypadku cz\u0119stych uruchomie\u0144 mypy bez u\u017cycia pami\u0119ci podr\u0119cznej. Rozw\u00f3j rdzenia projektu mypyc zaj\u0105\u0142 ma\u0142emu zespo\u0142owi, w sk\u0142ad kt\u00f3rego wchodzili Michael Sullivan, Ivan Levkivskiy, Hugh Han i ja, oko\u0142o 4 miesi\u0119cy kalendarzowych. Ten zakres pracy by\u0142 znacznie mniej rozleg\u0142y ni\u017c ten, kt\u00f3ry by\u0142by potrzebny do przepisywania mypy, na przyk\u0142ad w C++ lub Go. A dodatkowo wprowadzili\u015bmy do projektu znacznie mniej zmian, ni\u017c by\u0142oby konieczne w przypadku przepisywania go w innym j\u0119zyku. Mieli\u015bmy tak\u017ce nadziej\u0119, \u017ce uda nam si\u0119 doprowadzi\u0107 mypyc do takiego poziomu, aby mogli z niego korzysta\u0107 inni programi\u015bci z Dropbox, w celu kompilacji i przyspieszania swojego kodu.<\/p>\n<p>Aby osi\u0105gn\u0105\u0107 taki poziom wydajno\u015bci, musieli\u015bmy zastosowa\u0107 kilka interesuj\u0105cych rozwi\u0105za\u0144 in\u017cynieryjnych. Kompilator mo\u017ce przyspieszy\u0107 wykonanie wielu operacji dzi\u0119ki zastosowaniu szybkich, niskopoziomowych konstrukcji C. Na przyk\u0142ad, wywo\u0142anie skompilowanej funkcji jest przekszta\u0142cane w wywo\u0142anie funkcji C. Takie wywo\u0142anie jest znacznie szybsze od wywo\u0142ania funkcji interpretowanej. Niekt\u00f3re operacje, takie jak wyszukiwanie w s\u0142ownikach, nadal polega\u0142y na u\u017cywaniu zwyk\u0142ych wywo\u0142a\u0144 C-API z CPython, kt\u00f3re po skompilowaniu by\u0142y tylko nieco szybsze. Uda\u0142o nam si\u0119 pozby\u0107 dodatkowego obci\u0105\u017cenia systemu spowodowanego interpretacj\u0105, ale w tym przypadku przynios\u0142o to tylko niewielkie korzy\u015bci w zakresie wydajno\u015bci.<\/p>\n<p>Aby zidentyfikowa\u0107 najcz\u0119\u015bciej wyst\u0119puj\u0105ce operacje 'wolne', wykonali\u015bmy profilowanie kodu. Wyposa\u017ceni w uzyskane dane, pr\u00f3bowali\u015bmy \u043b\u0438\u0431\u043e dostosowa\u0107 mypyc, aby generowa\u0142 szybszy kod C dla takich operacji, \u043b\u0438\u0431\u043e przepisa\u0107 odpowiedni kod Python, u\u017cywaj\u0105c szybszych operacji (a czasami po prostu nie mieli\u015bmy wystarczaj\u0105co prostego rozwi\u0105zania dla danego problemu). Przepisywanie kodu Python cz\u0119sto okazywa\u0142o si\u0119 \u0142atwiejszym rozwi\u0105zaniem problemu ni\u017c wdro\u017cenie automatycznego wykonania tej samej transformacji w kompilatorze. W perspektywie d\u0142ugoterminowej chcieli\u015bmy zautomatyzowa\u0107 wiele z tych transformacji, ale w tamtym momencie koncentrowali\u015bmy si\u0119 na tym, aby, wk\u0142adaj\u0105c minimalny wysi\u0142ek, przyspieszy\u0107 mypy. I d\u0105\u017c\u0105c do tego celu, zredukowali\u015bmy kilka rog\u00f3w.<\/p>\n<p>Ci\u0105g dalszy nast\u0105pi\u2026<\/p>\n<p><b>Drodzy Czytelnicy!<\/b> Jakie wra\u017cenia wywar\u0142 na Tobie projekt mypy w momencie, gdy dowiedzia\u0142e\u015b si\u0119 o jego istnieniu?<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/vps_start\/\"><img decoding=\"async\" alt=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w linii kodu Python. Cz\u0119\u015b\u0107 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=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w linii kodu Python. Cz\u0119\u015b\u0107 2\" src=\"\/wp-content\/uploads\/2019\/09\/263173dd3ab487da330ff9063e3c180e.jpeg\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<br \/>\u0179r\u00f3d\u0142o: <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 5.0.1.1 - 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.\" \/>\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\/pl\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-2\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\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.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/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\udd47Droga do weryfikacji typ\u00f3w 4 milion\u00f3w linii kodu Python. Cz\u0119\u015b\u0107 2 | ProHoster","description":"Dzi\u015b publikujemy drug\u0105 cz\u0119\u015b\u0107 t\u0142umaczenia materia\u0142u o tym, jak w Dropboxie zorganizowano kontrol\u0119 typ\u00f3w kilku milion\u00f3w linii kodu Python.","canonical_url":"https:\/\/prohoster.info\/pl\/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":"pl_PL","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.","og:url":"https:\/\/prohoster.info\/pl\/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":{"focus":[],"additional":[]},"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-08-11 12:50:31","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/38479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=38479"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/38479\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/28879"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=38479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=38479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=38479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}