{"id":38649,"date":"2019-10-31T22:25:04","date_gmt":"2019-10-31T19:25:04","guid":{"rendered":"https:\/\/prohoster.info\/blog\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-3\/"},"modified":"2019-10-31T22:25:04","modified_gmt":"2019-10-31T19:25:04","slug":"put-k-proverke-tipov-4-millionov-strok-python-koda-chast-3","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-3","title":{"rendered":"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w wierszy kodu Python. Cz\u0119\u015b\u0107 3","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Przedstawiamy Pa\u0144stwu trzeci\u0105 cz\u0119\u015b\u0107 t\u0142umaczenia materia\u0142u o drodze, jak\u0105 przesz\u0142a firma Dropbox, wdra\u017caj\u0105c u siebie system sprawdzania typ\u00f3w kodu Python.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468237\/\"><img decoding=\"async\" alt=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w wierszy kodu Python. Cz\u0119\u015b\u0107 3\" src=\"\/wp-content\/uploads\/2019\/10\/757669265e870de604388c66adef814d.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p>\u2192 Poprzednie cz\u0119\u015bci: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468233\/\">pierwsza<\/a><\/noindex> i <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\">druga<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Osi\u0105gni\u0119cie 4 milion\u00f3w linii typowanego kodu<\/h2>\n<p>\nKolejnym wa\u017cnym zadaniem (by\u0142o to drug\u0105 najpopularniejsz\u0105 kwesti\u0105, kt\u00f3ra nurtowa\u0142a uczestnik\u00f3w wewn\u0119trznych ankiet) by\u0142o zwi\u0119kszenie obj\u0119to\u015bci kodu w Dropbox, pokrytego sprawdzeniami typ\u00f3w. Wypr\u00f3bowali\u015bmy kilka podej\u015b\u0107 do rozwi\u0105zania tego zadania \u2014 od naturalnego wzrostu obj\u0119to\u015bci bazy kodu typowanego do skoncentrowania wysi\u0142k\u00f3w cz\u0142onk\u00f3w zespo\u0142u mypy na statycznym i dynamicznym automatycznym wnioskowaniu typ\u00f3w. Ostatecznie sprawia\u0142o to wra\u017cenie, \u017ce nie ma prostej strategii zyskownej, ale uda\u0142o nam si\u0119 osi\u0105gn\u0105\u0107 szybki wzrost obj\u0119to\u015bci kodu z adnotacjami, \u0142\u0105cz\u0105c wiele podej\u015b\u0107.<\/p>\n<p>W rezultacie w naszym najwi\u0119kszym repozytorium Python (z kodem backendowym) liczba linii kodu z adnotacjami osi\u0105gn\u0119\u0142a niemal 4 miliony. Prace nad statyczn\u0105 typizacj\u0105 kodu trwa\u0142y oko\u0142o trzech lat. Mypy teraz wspiera r\u00f3\u017cne rodzaje raport\u00f3w o pokryciu kodu typami, kt\u00f3re u\u0142atwiaj\u0105 monitorowanie post\u0119pu typizacji. W szczeg\u00f3lno\u015bci mo\u017cemy generowa\u0107 raporty dotycz\u0105ce kodu z niepewno\u015bciami typ\u00f3w, takimi jak jawne u\u017cycie typu <code>Jak<\/code> w adnotacjach, kt\u00f3rych nie mo\u017cna zweryfikowa\u0107, lub takich, jak import zewn\u0119trznych bibliotek, w kt\u00f3rych brak adnotacji typ\u00f3w. W ramach projektu maj\u0105cego na celu popraw\u0119 dok\u0142adno\u015bci sprawdzania typ\u00f3w w Dropbox, przyczynili\u015bmy si\u0119 do ulepszenia definicji typ\u00f3w (tak zwanych plik\u00f3w stubbowych) dla niekt\u00f3rych popularnych otwartych bibliotek w zcentralizowanym repozytorium Pythona <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/python\/typeshed\">typeshed<\/a><\/noindex>.<\/p>\n<p>Wdro\u017cyli\u015bmy (i ustandaryzowali\u015bmy w kolejnych PEP) nowe mo\u017cliwo\u015bci systemu typ\u00f3w, kt\u00f3re pozwalaj\u0105 na u\u017cycie bardziej precyzyjnych typ\u00f3w dla niekt\u00f3rych specyficznych wzorc\u00f3w Pythona. Zauwa\u017calnym przyk\u0142adem tego jest <code>TypeDict<\/code>, kt\u00f3ry oferuje typy dla s\u0142ownik\u00f3w podobnych do JSON, maj\u0105cych ustalony zestaw kluczy tekstowych, z kt\u00f3rych ka\u017cdy ma warto\u015b\u0107 swojego typu. B\u0119dziemy kontynuowa\u0107 rozwijanie systemu typ\u00f3w. Prawdopodobnie naszym nast\u0119pnym krokiem b\u0119dzie poprawa wsparcia dla mo\u017cliwo\u015bci Pythona w zakresie operacji na liczbach.<\/p>\n<p><img decoding=\"async\" alt=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w wierszy kodu Python. Cz\u0119\u015b\u0107 3\" src=\"\/wp-content\/uploads\/2019\/10\/297b9e823141d6cb0d2f19f9a78a1153.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Liczba linii kodu z adnotacjami: serwer<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w wierszy kodu Python. Cz\u0119\u015b\u0107 3\" src=\"\/wp-content\/uploads\/2019\/10\/c183a9227e51d847bfdb2b8f6153684f.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Liczba linii kodu z adnotacjami: klient<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Droga do weryfikacji typ\u00f3w 4 milion\u00f3w wierszy kodu Python. Cz\u0119\u015b\u0107 3\" src=\"\/wp-content\/uploads\/2019\/10\/0a8b936fa454a34c09a9c6a2694485c9.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Ca\u0142kowita liczba linii kodu z adnotacjami<\/i><\/p>\n<p>Oto przegl\u0105d g\u0142\u00f3wnych cech dzia\u0142a\u0144, kt\u00f3re podj\u0119li\u015bmy w celu zwi\u0119kszenia liczby adnotowanych linii kodu w Dropboxie:<\/p>\n<p>\u015acis\u0142o\u015b\u0107 adnotacji. Stopniowo podnosili\u015bmy wymagania dotycz\u0105ce \u015bcis\u0142o\u015bci adnotacji nowego kodu. Zacz\u0119li\u015bmy od sugestii linterskich, kt\u00f3re zaleca\u0142y dodawanie adnotacji do plik\u00f3w, w kt\u00f3rych ju\u017c by\u0142y pewne adnotacje. Teraz wymagamy obecno\u015bci adnotacji typ\u00f3w w nowych plikach Python i w wi\u0119kszo\u015bci istniej\u0105cych plik\u00f3w.<\/p>\n<p>Raporty o typowaniu. Co tydzie\u0144 wysy\u0142amy zespo\u0142om raporty na temat poziomu typowania ich kodu i dajemy wskaz\u00f3wki dotycz\u0105ce tego, co powinno by\u0107 adnotowane w pierwszej kolejno\u015bci.<\/p>\n<p>Promocja mypy. Opowiadamy o mypy na r\u00f3\u017cnych wydarzeniach i komunikujemy si\u0119 z zespo\u0142ami, pomagaj\u0105c im zacz\u0105\u0107 korzysta\u0107 z adnotacji typ\u00f3w.<\/p>\n<p>Ankiety. Przeprowadzamy regularne ankiety u\u017cytkownik\u00f3w, aby zidentyfikowa\u0107 g\u0142\u00f3wne problemy. Jeste\u015bmy gotowi p\u00f3j\u015b\u0107 wystarczaj\u0105co daleko w ich rozwi\u0105zaniu (a\u017c do stworzenia nowego j\u0119zyka, aby przyspieszy\u0107 mypy!).<\/p>\n<p>Wydajno\u015b\u0107. Znacz\u0105co poprawili\u015bmy wydajno\u015b\u0107 mypy dzi\u0119ki zastosowaniu demona i mypyc. Zrobili\u015bmy to, aby zniwelowa\u0107 niedogodno\u015bci zwi\u0105zane z adnotowaniem oraz aby m\u00f3c pracowa\u0107 z du\u017cymi ilo\u015bciami kodu.<\/p>\n<p>Integracja z edytorami. Stworzyli\u015bmy narz\u0119dzia wspieraj\u0105ce uruchamianie mypy w popularnych edytorach u\u017cywanych w Dropboxie. Nale\u017c\u0105 do nich PyCharm, Vim i VS Code. Znacz\u0105co u\u0142atwi\u0142o to proces adnotowania kodu oraz weryfikacji jego dzia\u0142ania. Takie dzia\u0142ania s\u0105 zwykle charakterystyczne podczas adnotowania istniej\u0105cego kodu.<\/p>\n<p>Analiza statyczna. Stworzyli\u015bmy narz\u0119dzie do generowania sygnatur funkcji przy u\u017cyciu \u015brodk\u00f3w analizy statycznej. To narz\u0119dzie mo\u017ce dzia\u0142a\u0107 tylko w stosunkowo prostych sytuacjach, ale pomog\u0142o nam bez wi\u0119kszego wysi\u0142ku zwi\u0119kszy\u0107 pokrycie kodu typami.<\/p>\n<p>Wsparcie dla bibliotek zewn\u0119trznych. W wielu naszych projektach u\u017cywany jest zestaw narz\u0119dzi SQLAlchemy. Wykorzystuje on dynamiczne mo\u017cliwo\u015bci Pythona, kt\u00f3re typy PEP 484 nie s\u0105 w stanie odwzorowa\u0107 bezpo\u015brednio. Stworzyli\u015bmy odpowiedni plik stub zgodnie z PEP 561 i napisali\u015bmy wtyczk\u0119 do mypy.<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dropbox\/sqlalchemy-stubs\">otwarto\u017ar\u00f3d\u0142owy<\/a><\/noindex>), poprawiaj\u0105cy obs\u0142ug\u0119 SQLAlchemy.<\/p>\n<h2>Trudno\u015bci, z kt\u00f3rymi si\u0119 spotkali\u015bmy<\/h2>\n<p>\nDroga do 4 milion\u00f3w wierszy typowanego kodu nie zawsze by\u0142a dla nas \u0142atwa. Na tej drodze napotkali\u015bmy wiele przeszk\u00f3d i pope\u0142nili\u015bmy kilka b\u0142\u0119d\u00f3w. Oto niekt\u00f3re z problem\u00f3w, z kt\u00f3rymi si\u0119 zmierzyli\u015bmy. Mamy nadziej\u0119, \u017ce opowie\u015b\u0107 o nich pomo\u017ce innym unikn\u0105\u0107 podobnych problem\u00f3w.<\/p>\n<p>Brakuj\u0105ce pliki. Zaczynali\u015bmy prac\u0119 od sprawdzania tylko niewielkiej liczby plik\u00f3w. Wszystko, co nie wchodzi\u0142o w sk\u0142ad tej liczby, nie by\u0142o sprawdzane. Pliki dodawano do listy kontrolnej, gdy pojawia\u0142y si\u0119 w nich pierwsze adnotacje. Je\u015bli co\u015b by\u0142o importowane z modu\u0142u znajduj\u0105cego si\u0119 poza obszarem kontroli, mowa by\u0142a o pracy z warto\u015bciami typu <code>Jak<\/code>, kt\u00f3re w og\u00f3le nie by\u0142y sprawdzane. Prowadzi\u0142o to do znacznej utraty precyzji typowania, szczeg\u00f3lnie na wczesnych etapach migracji. Taki spos\u00f3b dzia\u0142ania nadal zaskakuj\u0105co dobrze funkcjonowa\u0142, chocia\u017c typow\u0105 sytuacj\u0105 by\u0142o to, \u017ce dodanie plik\u00f3w do obszaru kontroli ujawnia\u0142o problemy w innych cz\u0119\u015bciach bazy kodu. W najgorszym przypadku, gdy \u0142\u0105czono dwa izolowane obszary kodu, w kt\u00f3rych typy by\u0142y ju\u017c niezale\u017cnie sprawdzone, okazywa\u0142o si\u0119, \u017ce typy tych obszar\u00f3w by\u0142y ze sob\u0105 niekompatybilne. To prowadzi\u0142o do konieczno\u015bci wprowadzenia wielu zmian w adnotacjach. Patrz\u0105c wstecz, rozumiemy, \u017ce powinni\u015bmy jak najszybciej doda\u0107 do obszaru kontroli typ\u00f3w mypy podstawowe modu\u0142y biblioteczne. To uczyni\u0142oby nasz\u0105 prac\u0119 znacznie bardziej przewidywaln\u0105.<\/p>\n<p>Annotacja starego kodu. Kiedy zaczynali\u015bmy prac\u0119, mieli\u015bmy oko\u0142o 4 milion\u00f3w ju\u017c istniej\u0105cych linii kodu w Pythonie. By\u0142o jasne, \u017ce annotacja ca\u0142ego tego kodu to nie\u0142atwe zadanie. Stworzyli\u015bmy narz\u0119dzie o nazwie PyAnnotate, kt\u00f3re mo\u017ce zbiera\u0107 informacje o typach w trakcie wykonywania test\u00f3w i potrafi dodawa\u0107 do kodu adnotacje typ\u00f3w, opieraj\u0105c si\u0119 na zebranych danych. Jednak nie zauwa\u017cyli\u015bmy szczeg\u00f3lnego rozpowszechnienia tego narz\u0119dzia. Zbieranie informacji o typach by\u0142o wolne, a automatycznie generowane adnotacje cz\u0119sto wymaga\u0142y wielu r\u0119cznych poprawek. My\u015bleli\u015bmy o automatycznym uruchomieniu tego narz\u0119dzia przy ka\u017cdej kontroli kodu lub o zbieraniu informacji o typach na podstawie analizy niewielkiej ilo\u015bci rzeczywistych zapyta\u0144 sieciowych, ale postanowili\u015bmy tego nie robi\u0107, poniewa\u017c kt\u00f3rykolwiek z tych podej\u015b\u0107 by\u0142by zbyt ryzykowny.<\/p>\n<p>W ko\u0144cu mo\u017cna zauwa\u017cy\u0107, \u017ce wi\u0119kszo\u015b\u0107 kodu zosta\u0142a r\u0119cznie adnotowana przez jego w\u0142a\u015bcicieli. Aby skierowa\u0107 ten proces w w\u0142a\u015bciwym kierunku, przygotowujemy raporty na temat szczeg\u00f3lnie wa\u017cnych modu\u0142\u00f3w i funkcji, kt\u00f3re trzeba adnotowa\u0107. Na przyk\u0142ad, wa\u017cne jest, aby dostarczy\u0107 adnotacje typ\u00f3w do modu\u0142u bibliotecznego u\u017cywanego w setkach miejsc. Natomiast stary serwis, kt\u00f3ry jest zast\u0119powany nowym, nie jest ju\u017c tak wa\u017cny do adnotowania. Dodatkowo eksperymentujemy z wykorzystaniem analizy statycznej do generowania adnotacji typ\u00f3w dla starego kodu.<\/p>\n<p>Importy cykliczne. Wcze\u015bniej wspomnia\u0142em o cyklicznych importach (o \u201eplecionkach zale\u017cno\u015bci\u201d), kt\u00f3rych istnienie skomplikowa\u0142o przyspieszenie mypy. Musieli\u015bmy tak\u017ce wykona\u0107 powa\u017cn\u0105 prac\u0119, aby zapewni\u0107 mypy wsparcie dla wszystkich rodzaj\u00f3w idiom\u00f3w, kt\u00f3rych przyczyn\u0105 s\u0105 te cykliczne importy. Niedawno zako\u0144czyli\u015bmy du\u017cy projekt redesignu systemu, kt\u00f3ry naprawi\u0142 wi\u0119kszo\u015b\u0107 problem\u00f3w mypy zwi\u0105zanych z cyklicznymi importami. Problemy te wywodzi\u0142y si\u0119 w rzeczywisto\u015bci z bardzo wczesnych dni projektu, jeszcze z Alore, j\u0119zyka nauczania, na kt\u00f3rym pierwotnie oparty by\u0142 projekt mypy. Sk\u0142adnia Alore \u0142atwo rozwi\u0105zywa\u0142a problemy cyklicznych import\u00f3w. Nowoczesny mypy odziedziczy\u0142 pewne ograniczenia ze swojej wczesnej, nieco prymitywnej implementacji (kt\u00f3ra \u015bwietnie pasowa\u0142a do Alore). Python utrudnia prac\u0119 z cyklicznymi importami g\u0142\u00f3wnie z powodu niejednoznaczno\u015bci wyra\u017ce\u0144. Na przyk\u0142ad, w trakcie operacji przypisania warto\u015b\u0107 mo\u017ce rzeczywi\u015bcie zosta\u0107 okre\u015blona przez alias typu. Mypy nie zawsze jest w stanie wykry\u0107 tego typu rzeczy, dop\u00f3ki wi\u0119kszo\u015b\u0107 cyklu importu nie zostanie przetworzona. W Alore takich niejednoznaczno\u015bci nie by\u0142o. Niefortunne decyzje podj\u0119te na wczesnych etapach rozwoju systemu mog\u0105 zaskoczy\u0107 programist\u0119 po wielu latach.<\/p>\n<h2>Podsumowanie: droga do 5 milion\u00f3w linii kodu i nowych horyzont\u00f3w<\/h2>\n<p>\nProjekt mypy przeszed\u0142 d\u0142ug\u0105 drog\u0119 \u2014 od wczesnych prototyp\u00f3w po system, kt\u00f3ry kontroluje typy kodu produkcyjnego o obj\u0119to\u015bci 4 milion\u00f3w linii. W trakcie rozwoju mypy zosta\u0142a zrealizowana standaryzacja wskaz\u00f3wek dotycz\u0105cych typ\u00f3w w Pythonie. Dzi\u015b wok\u00f3\u0142 typizacji kodu Pythona rozwin\u0119\u0142a si\u0119 pot\u0119\u017cna ekosystem. Mie\u015bci on wsparcie dla bibliotek, zawiera narz\u0119dzia pomocnicze dla IDE i edytor\u00f3w, a tak\u017ce kilka system\u00f3w kontroli typ\u00f3w, z kt\u00f3rych ka\u017cdy ma swoje plusy i minusy.<\/p>\n<p>Pomimo \u017ce sprawdzanie typ\u00f3w jest ju\u017c postrzegane w Dropbox jako co\u015b oczywistego, jestem pewny, \u017ce nadal \u017cyjemy na pocz\u0105tku ery typizacji kodu Pythona. My\u015bl\u0119, \u017ce technologie sprawdzania typ\u00f3w b\u0119d\u0105 nadal si\u0119 rozwija\u0107 i doskonali\u0107.<\/p>\n<p>Je\u015bli jeszcze nie korzysta\u0142e\u015b z kontroli typ\u00f3w w swoim du\u017cym projekcie Python, wiedz, \u017ce teraz jest doskona\u0142y moment, aby rozpocz\u0105\u0107 przej\u015bcie na statyczne typowanie. Rozmawia\u0142em z osobami, kt\u00f3re dokona\u0142y podobnego przej\u015bcia. Nikt z nich tego nie \u017ca\u0142owa\u0142. Kontrola typ\u00f3w sprawia, \u017ce Python staje si\u0119 j\u0119zykiem znacznie lepiej przystosowanym do tworzenia du\u017cych projekt\u00f3w ni\u017c \"zwyk\u0142y Python\".<\/p>\n<p><b>Drodzy Czytelnicy!<\/b> Czy korzystasz z kontroli typ\u00f3w w swoich projektach Python?<\/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 wierszy kodu Python. Cz\u0119\u015b\u0107 3\" src=\"\/wp-content\/uploads\/2019\/10\/bf2bc557ce4481dd87398515bff60e3f.png\" 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 wierszy kodu Python. Cz\u0119\u015b\u0107 3\" src=\"\/wp-content\/uploads\/2019\/10\/098d481c25b3afaba9534c686e8f943a.png\" 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\/468237\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u0442\u0440\u0435\u0442\u044c\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u043f\u0443\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0448\u043b\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Dropbox, \u0432\u043d\u0435\u0434\u0440\u044f\u044f \u0443 \u0441\u0435\u0431\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u043e\u0432 Python-\u043a\u043e\u0434\u0430. \u2192 \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0435 \u0447\u0430\u0441\u0442\u0438: \u043f\u0435\u0440\u0432\u0430\u044f \u0438 \u0432\u0442\u043e\u0440\u0430\u044f \u0414\u043e\u0441\u0442\u0438\u0436\u0435\u043d\u0438\u0435 4 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u043e\u0432 \u0441\u0442\u0440\u043e\u043a \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0415\u0449\u0451 \u043e\u0434\u043d\u043e\u0439 \u0432\u0430\u0436\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439 (\u044d\u0442\u043e \u0431\u044b\u043b \u0432\u0442\u043e\u0440\u0430\u044f \u043f\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0432\u043e\u043b\u043d\u043e\u0432\u0430\u0432\u0448\u0430\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u043b \u0432\u043e \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u043e\u043f\u0440\u043e\u0441\u0430\u0445) \u0431\u044b\u043b\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435 \u043e\u0431\u044a\u0451\u043c\u0430 \u043a\u043e\u0434\u0430 \u0432 Dropbox, [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":28992,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38649","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=\"\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u0442\u0440\u0435\u0442\u044c\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u043f\u0443\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0448\u043b\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Dropbox, \u0432\u043d\u0435\u0434\u0440\u044f\u044f \u0443 \u0441\u0435\u0431\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u043e\u0432 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-3\" \/>\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 3 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u0442\u0440\u0435\u0442\u044c\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u043f\u0443\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0448\u043b\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Dropbox, \u0432\u043d\u0435\u0434\u0440\u044f\u044f \u0443 \u0441\u0435\u0431\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u043e\u0432 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-3\" \/>\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:25:04+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:25:04+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 kontroli typ\u00f3w w 4 milionach linii kodu Python. Cz\u0119\u015b\u0107 3 | ProHoster","description":"Przedstawiamy Pa\u0144stwu trzeci\u0105 cz\u0119\u015b\u0107 t\u0142umaczenia materia\u0142u o drodze, jak\u0105 przesz\u0142a firma Dropbox, wdra\u017caj\u0105c u siebie system sprawdzania typ\u00f3w kodu Python.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-3","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 3 | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e \u0442\u0440\u0435\u0442\u044c\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430 \u043e \u043f\u0443\u0442\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u043e\u0448\u043b\u0430 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044f Dropbox, \u0432\u043d\u0435\u0434\u0440\u044f\u044f \u0443 \u0441\u0435\u0431\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u0438\u043f\u043e\u0432 Python-\u043a\u043e\u0434\u0430.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-3","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:25:04+00:00","article:modified_time":"2019-10-31T19:25:04+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38649","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:54:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 01:05:23","updated":"2026-08-11 12:50:30","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\/38649","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=38649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/38649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/28992"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=38649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=38649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=38649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}