{"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\/ro\/blog\/administrirovanie\/put-k-proverke-tipov-4-millionov-strok-python-koda-chast-3","title":{"rendered":"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 3","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>V\u0103 prezent\u0103m partea a treia a traducerii materialului despre parcursul companiei Dropbox \u00een implementarea sistemului de verificare a tipurilor de cod Python.<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468237\/\"><img decoding=\"async\" alt=\"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 3\" src=\"\/wp-content\/uploads\/2019\/10\/757669265e870de604388c66adef814d.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><\/p>\n<p>\u2192 P\u0103r\u021bile anterioare: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468233\/\">prima<\/a><\/noindex> \u0219i <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/ruvds\/blog\/468235\/\">a doua<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Realizarea a 4 milioane de linii de cod tipizat<\/h2>\n<p>\nO alt\u0103 sarcin\u0103 important\u0103 (aceasta fiind a doua problem\u0103 ca popularitate care a st\u00e2rnit interesul celor care au participat la sondajele interne) a fost cre\u0219terea volumului de cod din Dropbox acoperit de verific\u0103rile de tipuri. Am \u00eencercat mai multe abord\u0103ri pentru a rezolva aceast\u0103 problem\u0103 \u2014 de la cre\u0219terea natural\u0103 a volumului bazei de cod tipizat\u0103 p\u00e2n\u0103 la concentrare pe eforturile membrilor echipei mypy pe inferen\u021ba static\u0103 \u0219i dinamic\u0103 a tipurilor automatizate. \u00cen final, a fost creat\u0103 impresia c\u0103 nu exist\u0103 o strategie c\u00e2\u0219tig\u0103toare simpl\u0103, dar am reu\u0219it s\u0103 ob\u021binem o cre\u0219tere rapid\u0103 a volumului de cod anun\u021bat, combin\u00e2nd mai multe abord\u0103ri.<\/p>\n<p>Astfel, \u00een cel mai mare depozit Python al nostru (cu cod de backend), num\u0103rul de linii de cod anun\u021bat a ajuns la aproape 4 milioane. Lucr\u0103rile privind tipizarea static\u0103 a codului au fost desf\u0103\u0219urate pe parcursul a aproximativ trei ani. Mypy acum suport\u0103 diverse tipuri de rapoarte despre acoperirea codului cu tipuri, care simplific\u0103 monitorizarea progresului tipiz\u0103rii. \u00cen special, putem genera rapoarte pentru cod cu ambiguit\u0103\u021bi \u00een tipuri, cum ar fi utilizarea explicit\u0103 a tipului <code>Any<\/code> \u00een adnot\u0103ri, care nu pot fi verificate, sau \u00een cazul importului de biblioteci externe care nu au adnot\u0103ri de tipuri. \u00cen cadrul proiectului nostru de \u00eembun\u0103t\u0103\u021bire a preciziei verific\u0103rii tipurilor \u00een Dropbox, am contribuit la \u00eembun\u0103t\u0103\u021birea defini\u021biilor de tipuri (a\u0219a-numitele fi\u0219iere stub) pentru unele biblioteci popolare open-source \u00een depozitul centralizat Python <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/python\/typeshed\">typeshed<\/a><\/noindex>.<\/p>\n<p>Am implementat (\u0219i standardizat \u00een PEP-urile ulterioare) noi capabilit\u0103\u021bi ale sistemului de tipuri, care permit utilizarea unor tipuri mai precise pentru anumite tipare specifice Python. Un exemplu notabil al acestui lucru este <code>TypeDict<\/code>, care ofer\u0103 tipuri pentru dic\u021bionarele asem\u0103n\u0103toare JSON cu un set fix de chei string, fiecare av\u00e2nd o valoare de tip propriu. Vom continua s\u0103 extindem sistemul de tipuri. Probabil c\u0103 urm\u0103torul nostru pas va fi \u00eembun\u0103t\u0103\u021birea suportului pentru capabilit\u0103\u021bile Python de gestionare a numerelor.<\/p>\n<p><img decoding=\"async\" alt=\"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 3\" src=\"\/wp-content\/uploads\/2019\/10\/297b9e823141d6cb0d2f19f9a78a1153.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Num\u0103rul de linii de cod anun\u021bat: server<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 3\" src=\"\/wp-content\/uploads\/2019\/10\/c183a9227e51d847bfdb2b8f6153684f.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Num\u0103rul de linii de cod annotate: client<\/i><\/p>\n<p><img decoding=\"async\" alt=\"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 3\" src=\"\/wp-content\/uploads\/2019\/10\/0a8b936fa454a34c09a9c6a2694485c9.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Num\u0103rul total de linii de cod annotate<\/i><\/p>\n<p>Iat\u0103 o prezentare general\u0103 a principalelor caracteristici ale ac\u021biunilor pe care le-am desf\u0103\u0219urat pentru a cre\u0219te volumul de cod annotate \u00een Dropbox:<\/p>\n<p>Rigurozitatea anot\u0103rii. Am crescut treptat cerin\u021bele privind rigurozitatea anot\u0103rii noului cod. Am \u00eenceput cu sugestiile linters-ului, care recomandau ad\u0103ugarea de anota\u021bii \u00een fi\u0219ierele care aveau deja unele anota\u021bii. Acum cerem prezen\u021ba anota\u021biilor de tip \u00een fi\u0219ierele noi Python \u0219i \u00een majoritatea fi\u0219ierelor existente.<\/p>\n<p>Rapoartele de tipare. Trimitem echipelor rapoarte s\u0103pt\u0103m\u00e2nale privind nivelul de tipare a codului lor \u0219i oferim sugestii despre ce anume ar trebui s\u0103 fie annotate mai \u00eent\u00e2i.<\/p>\n<p>Promovarea mypy. Vorbim despre mypy la diferite evenimente \u0219i comunic\u0103m cu echipele, ajut\u00e2ndu-le s\u0103 \u00eenceap\u0103 s\u0103 foloseasc\u0103 anota\u021biile de tip.<\/p>\n<p>Sondajele. Efectu\u0103m sondaje periodice \u00een r\u00e2ndul utilizatorilor pentru a identifica problemele principale. Suntem preg\u0103ti\u021bi s\u0103 mergem destul de departe \u00een solu\u021bionarea acestor probleme (chiar \u0219i cre\u00e2nd o nou\u0103 limb\u0103 pentru a accelera mypy!).<\/p>\n<p>Performan\u021ba. Am \u00eembun\u0103t\u0103\u021bit semnificativ performan\u021ba mypy prin utilizarea demonului \u0219i a mypyc. Acest lucru a fost realizat pentru a netezi disconforturile ap\u0103rute \u00een procesul de annotare \u0219i pentru a permite lucrul cu volume mari de cod.<\/p>\n<p>Integrarea cu editorii. Am creat instrumente pentru a sprijini rularea mypy \u00een editorii populari \u00een Dropbox. Acestea includ PyCharm, Vim \u0219i VS Code. Acest lucru a simplificat semnificativ procesul de realizare a lucr\u0103rilor de annotare a codului \u0219i de verificare a func\u021bion\u0103rii sale. Astfel de ac\u021biuni sunt de obicei caracteristice atunci c\u00e2nd se anoteaz\u0103 cod existent.<\/p>\n<p>Analiza static\u0103. Am creat un instrument pentru generarea semn\u0103turilor func\u021biilor folosind instrumente de analiz\u0103 static\u0103. Acest instrument poate func\u021biona doar \u00een situa\u021bii relativ simple, dar ne-a ajutat s\u0103 cre\u0219tem acoperirea codului cu tipuri f\u0103r\u0103 prea mult efort.<\/p>\n<p>Suport pentru biblioteci externe. \u00cen multe dintre proiectele noastre folosim un set de instrumente SQLAlchemy. Acesta utilizeaz\u0103 capabilit\u0103\u021bile dinamice ale Python, pe care tipurile PEP 484 nu le pot modela direct. Conform PEP 561, am creat un fi\u0219ier stub corespunz\u0103tor \u0219i am scris un plugin pentru mypy.<noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dropbox\/sqlalchemy-stubs\">open-source<\/a><\/noindex>), \u00eembun\u0103t\u0103\u021bind suportul pentru SQLAlchemy.<\/p>\n<h2>Dificult\u0103\u021bile \u00eent\u00e2mpinate<\/h2>\n<p>\nDrumul c\u0103tre 4 milioane de linii de cod tipizat nu a fost \u00eentotdeauna u\u0219or. Pe acest parcurs, am \u00eent\u00e2lnit multe obstacole \u0219i am f\u0103cut c\u00e2teva gre\u0219eli. Iat\u0103 c\u00e2teva dintre problemele cu care ne-am confruntat. Sper\u0103m c\u0103 povestirea acestora va ajuta al\u021bii s\u0103 evite probleme similare.<\/p>\n<p>Fi\u0219iere omise. Am \u00eenceput lucrul verific\u00e2nd doar un volum mic de fi\u0219iere. Tot ce nu se afla \u00een num\u0103rul acestor fi\u0219iere nu era verificat. Fi\u0219ierele erau ad\u0103ugate pe lista de verificare atunci c\u00e2nd ap\u0103reau primele comentarii. Dac\u0103 ceva era importat dintr-un modul situat \u00een afara domeniului de verificare, era vorba despre lucrul cu valori de tip <code>Any<\/code>, care nu erau verificate deloc. Aceasta a dus la o pierdere semnificativ\u0103 a preciziei tipiz\u0103rii, \u00een special \u00een etapele timpurii ale migra\u021biei. Aceast\u0103 abordare a func\u021bionat surprinz\u0103tor de bine, de\u0219i situa\u021bia tipic\u0103 era c\u0103 ad\u0103ugarea fi\u0219ierelor \u00een domeniul de verificare scotea la iveal\u0103 probleme \u00een alte p\u0103r\u021bi ale bazei de cod. \u00cen cel mai r\u0103u caz, c\u00e2nd se \u00eembinau dou\u0103 domenii izolate de cod, \u00een care, \u00een mod independent unul de cel\u0103lalt, tipurile fuseser\u0103 deja verificate, se descoperea c\u0103 tipurile acestor domenii nu erau compatibile \u00eentre ele. Aceasta a dus la necesitatea de a face multe modific\u0103ri \u00een comentarii. Acum, privind \u00eenapoi, ne d\u0103m seama c\u0103 ar fi trebuit s\u0103 ad\u0103ug\u0103m c\u00e2t mai cur\u00e2nd posibil modulele bibliotecare de baz\u0103 \u00een domeniul de verificare a tipurilor mypy. Aceasta ar fi f\u0103cut munca noastr\u0103 mult mai previzibil\u0103.<\/p>\n<p>Annotarea codului vechi. C\u00e2nd am \u00eenceput lucrul, aveam aproximativ 4 milioane de linii de cod Python existent. Era clar c\u0103 annotarea \u00eentregului acestui cod era o sarcin\u0103 dificil\u0103. Am creat un instrument numit PyAnnotate, care poate colecta informa\u021bii despre tipuri \u00een timpul testelor \u0219i poate ad\u0103uga \u00een cod anot\u0103ri de tip, baz\u00e2ndu-se pe informa\u021biile colectate. Cu toate acestea, nu am observat o adoptare foarte larg\u0103 a acestui instrument. Colectarea informa\u021biilor despre tipuri era lent\u0103, iar anot\u0103rile generate automat necesitau adesea multe modific\u0103ri manuale. Ne-am g\u00e2ndit la lansarea automat\u0103 a acestui instrument la fiecare verificare a codului sau s\u0103 colect\u0103m informa\u021biile despre tipuri, baz\u00e2ndu-ne pe analiza unui volum mic de cereri reale de re\u021bea, dar am decis s\u0103 nu facem acest lucru, deoarece oricare dintre aceste abord\u0103ri era prea riscant.<\/p>\n<p>\u00cen concluzie, se poate men\u021biona c\u0103 cea mai mare parte a codului a fost annotat\u0103 manual de c\u0103tre proprietarii s\u0103i. Noi, pentru a orienta acest proces \u00een direc\u021bia corect\u0103, preg\u0103tim rapoarte pentru modulele \u0219i func\u021biile deosebit de importante care trebuie annotate. De exemplu, este important s\u0103 furniz\u0103m anot\u0103ri de tip pentru un modul de bibliotec\u0103 utilizat \u00een sute de locuri. \u00cen schimb, un serviciu vechi, care este \u00eenlocuit cu unul nou, nu mai este la fel de important s\u0103 fie annotat. De asemenea, experiment\u0103m cu utilizarea analizei statice pentru a genera anot\u0103ri de tip pentru codul vechi.<\/p>\n<p>Importuri circulare. Am men\u021bionat mai sus despre importurile circulare (despre \"ghemotocurile de dependen\u021be\"), al c\u0103ror existen\u021b\u0103 a complicat accelerarea mypy. De asemenea, a fost necesar s\u0103 lucr\u0103m serios pentru a oferi mypy suport pentru toate tipurile de idiomuri, cauzate de aceste importuri circulare. Recent, am finalizat un proiect major de redesign al sistemului, care a remediat majoritatea problemelor mypy legate de importurile circulare. Aceste probleme, de fapt, \u00ee\u0219i au r\u0103d\u0103cinile \u00een vremurile foarte timpurii ale proiectului, \u00eenc\u0103 din Alore, limbajul de \u00eenv\u0103\u021bare pe care s-a concentrat ini\u021bial proiectul mypy. Sintaxa Alore permite rezolvarea u\u0219oar\u0103 a problemelor cu importurile circulare. Mypy modern a mo\u0219tenit anumite limit\u0103ri de la implementarea sa timpurie simpl\u0103 (care se potrivea perfect pentru Alore). Python complic\u0103 lucrul cu importurile circulare, \u00een principal din cauza ambiguit\u0103\u021bii expresiilor. De exemplu, \u00een timpul opera\u021biunii de atribu\u021bie a unei valori, aliasul tipului poate fi, de fapt, definit. Mypy nu este \u00eentotdeauna capabil s\u0103 identifice astfel de lucruri p\u00e2n\u0103 c\u00e2nd cea mai mare parte a ciclului de import nu este procesat\u0103. \u00cen Alore, astfel de ambiguit\u0103\u021bi nu existau. Deciziile nereu\u0219ite luate \u00een etapele timpurii de dezvoltare a sistemului pot aduce programatorului o surpriz\u0103 nepl\u0103cut\u0103 mul\u021bi ani mai t\u00e2rziu.<\/p>\n<h2>Concluzii: drumul c\u0103tre 5 milioane de linii de cod \u0219i noi orizonturi<\/h2>\n<p>\nProiectul mypy a parcurs un drum lung \u2014 de la prototipuri timpurii p\u00e2n\u0103 la un sistem care controleaz\u0103 tipurile codului de produc\u021bie de 4 milioane de linii. Pe parcursul dezvolt\u0103rii mypy, s-a realizat standardizarea sugestiilor de tip \u00een Python. \u00cen zilele noastre, \u00een jurul tipiz\u0103rii codului Python s-a dezvoltat un ecosistem puternic. Acesta include suport pentru biblioteci, instrumente pentru IDE \u0219i editori, \u0219i exist\u0103 mai multe sisteme de control al tipurilor, fiecare av\u00e2nd propriile plusuri \u0219i minusuri.<\/p>\n<p>De\u0219i verificarea tipurilor este deja perceput\u0103 \u00een Dropbox ca un lucru evident, sunt sigur c\u0103 \u00eenc\u0103 tr\u0103im la \u00eenceputurile tipiz\u0103rii codului Python. Cred c\u0103 tehnologiile de verificare a tipurilor vor continua s\u0103 se dezvolte \u0219i s\u0103 se perfe\u021bioneze.<\/p>\n<p>Dac\u0103 nu a\u021bi folosit p\u00e2n\u0103 acum verific\u0103rile de tip \u00een proiectul dumneavoastr\u0103 Python la scar\u0103 larg\u0103, acum este un moment foarte potrivit s\u0103 \u00eencepe\u021bi tranzi\u021bia la tipizarea static\u0103. Am discutat cu cei care au realizat o astfel de tranzi\u021bie. Nimeni dintre ei nu a regretat acest lucru. Controlul tipurilor transform\u0103 Python \u00eentr-o limbaj care este mult mai potrivit pentru dezvoltarea de proiecte mari dec\u00e2t \"Python normal\".<\/p>\n<p><b>Stima\u021bi cititori!<\/b> Folosi\u021bi controlul tipurilor \u00een proiectele dumneavoastr\u0103 Python?<\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/ruvds.com\/vps_start\/\"><img decoding=\"async\" alt=\"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 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=\"Calea verificarilor pentru 4 milioane de linii de cod Python. Partea 3\" src=\"\/wp-content\/uploads\/2019\/10\/098d481c25b3afaba9534c686e8f943a.png\" style=\"display:block;margin: 0 auto;\" \/><\/a><\/noindex><br \/>\n<br \/>Sursa: <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.2.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\/ro\/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.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\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\/ro\/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\udd47Calea c\u0103tre verificarea tipurilor \u00een 4 milioane de linii de cod Python. Partea 3 | ProHoster","description":"V\u0103 prezent\u0103m partea a treia a traducerii materialului despre parcursul companiei Dropbox \u00een implementarea sistemului de verificare a tipurilor de cod Python.","canonical_url":"https:\/\/prohoster.info\/ro\/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":"ro_RO","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\/ro\/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\/ro\/wp-json\/wp\/v2\/posts\/38649","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=38649"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/38649\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media\/28992"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=38649"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=38649"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=38649"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}