Hacker News

Python Type Checker Comparaison: Inferenza di Container Vacu

Cumenti

12 min read Via pyrefly.org

Mewayz Team

Editorial Team

Hacker News

Perchè i Containers Viotu rompenu i Checkers di Python - è ciò chì pudete fà

U sistema di scrittura graduali di Python hà maturatu significativamente da chì PEP 484 hà introduttu suggerimenti di tipu in 2015. Oghje, milioni di sviluppatori si basanu in i verificatori di tippu staticu per catturà bug prima di chjappà a produzzione. Ma ci hè un angulu sottile è frustrante di u sistema di tipu chì viaghja ancu ancu ingegneri sperimentati: chì tipu hà un containeru viotu? Quandu scrivite x = []senza annotazione, u vostru verificatore di tipu hà da indovinà - è e diverse checkers guessinu in modu diversu. Questa divergenza crea prublemi veri per e squadre chì mantenenu una grande basa di codice, induve u cambiamentu o cumminazione di i verificatori di tippu ponu affruntà centinaie d'errori inaspettati durante a notte.

Stu articulu spiega cumu i quattru principali verificatori di tipu Python - mypy, pyright, pytype è pyre - trattanu l'inferenza di u containeru viotu, perchè ùn sò micca d'accordu, è quali strategie pratiche pudete aduttà per scrive Python senza tipu, indipendentemente da a vostra scelta di l'uttellu.

U Prublemu Core: I Containers Viotu sò Inherently Ambiguous

Considerate sta linea innocua di Python: risultati = []. I risultati sò una lista[int]? Una lista[str]? Una lista[dict[str, Any]]? Senza cuntestu supplementu, ùn ci hè veramente manera di sapè. U runtime di Python ùn importa micca - i listi sò eterogenei per natura - ma i verificatori di tipu staticu anu bisognu di assignà un tipu concreto à ogni variabile per fà u so travagliu. Questu crea una tensione fundamentale trà a flessibilità dinamica di Python è e garanzie chì l'analisi statica prova di furnisce.

U prublema cumposta cù dizziunari è setti. Un {} viotu hè in realtà analizatu cum'è un dict, micca un set, chì aghjunghje l'ambiguità sintattica in cima à l'ambiguità di livellu di tipu. E cuntenituri nidificatu - pensate defaultdict (list) o results = {k: [] for k in keys} - spinghje i mutori di inferenza à i so limiti. Ogni verificatore di tipu hà sviluppatu a so propria euristica, è e differenze sò più significative di ciò chì a maiò parte di i sviluppatori capiscenu.

In i sistemi di produzzione chì trattanu carichi di travagliu reali - sia un CRM chì gestisce i registri di i clienti, un modulu di fatturazione chì genera elementi di linea, o un pipeline analiticu chì aggrega metriche - i cuntenituri vioti appariscenu constantemente cum'è mudelli di inizializazione. Avè i so tipi sbagliati ùn solu pruduce avvisi di linter; pò maschere bugs genuine chì sdrughjenu à u runtime.

Mypy: Inferenza differita cù qualsiasi implicita

Mypy, u verificatore di tipu Python più anticu è aduttatu, adopta un approcciu relativamente indulgente à i cuntenituri vacanti. Quandu si scontra x = []à u scopu di a funzione, prova di differisce a decisione di tipuè inferisce u tipu di l'elementu da l'usu sussegwenti. Se scrivi x = [] seguita da x.append(42), mypy deducerà list[int]. Questa strategia "join" funziona sorprendentemente bè per i casi diretti induve u cuntinuu hè populatu in u stessu scopu.

Tuttavia, u cumpurtamentu di mypy cambia drasticamente secondu u cuntestu è i paràmetri di rigore. À u scopu di u modulu (codice di primu livellu), o quandu u cuntinuu hè passatu à una altra funzione prima di esse populatu, mypy spessu torna à list[Any]. Sottu a bandiera --strict, questu provoca un errore, ma in modu predeterminatu passa in silenziu. Questu significa chì e squadre chì eseguenu mypy senza u modu strettu ponu accumulà decine di cuntenituri implicitamente tipati chì agiscenu cum'è portelli di fuga da u sistema di tipu, scunfittendu u so scopu.

Un cumportamentu particularmente sottile: e versioni mypy prima di 0.990 anu qualchì volta inferisce list[Unknown] internamente è poi allargate à list[Any] in assignazione. Post-0.990, l'inferenza hè stata ristretta, ma u cambiamentu hà rottu un numeru sorprendente di codebases di u mondu reale chì avianu cunfidendu u cumpurtamentu permissiu senza avè capitu. Questu hè un tema recurrente - i cambiamenti à l'inferenza di u containeru viotu sò trà l'aghjurnamenti più disruptive di u verificatore di tipu perchè i mudelli sò cusì omnipresenti.

Pyright: Inferenza stretta è u tipu "Scunnutu"

Pyright, sviluppatu da Microsoft è alimentando Pylance in VS Code, assume una postura filosofica fundamentalmente diversa. Piuttostu cà silenziu falà à Qualsiasi, pyright distingue entre Sconnu(un tipu chì ùn hè statu ancu determinatu) è Qualsiasi(un opt-out esplicitu di cuntrollu di tipu). Quandu scrivite x = [] in u modu strettu di pyright, inferisce list[Unknown]è riporta un diagnosticu, furzendu à furnisce una annotazione.

Pyright hè ancu più aggressivu in quantu à restringe in u scopu. Se scrivi:

  • x = [] seguita da x.append("hello") - pyright infers list[str]
  • x = [] seguita da x.append(1) poi x.append("hello") — pyright infers list[int | str
  • x = [] passò direttamente à una funzione chì aspetta list[int] — pyright infers list[int] da u cuntestu di u situ di chjama
  • x = [] riturnatu da una funzione senza una annotazione di tipu di ritornu - pyright signala un errore piuttostu cà indovinà

Questa inferenza bidirezionale (aduprendu l'usu sussegwente è i tipi previsti da i siti di chjama) rende pyright notevolmente più precisa di mypy per i cuntenituri vacanti. U scambiu hè verbosità: u modu strettu di pyright signala circa 30-40% più prublemi nantu à una basa di codice tipica senza annotazioni cumparatu cù u modu strettu di mypy, secondu l'analisi di parechji rapporti di migrazione open-source. Per i squadre chì custruiscenu sistemi di backend cumplessi - per esempiu, una piattaforma chì gestisce 207 moduli interconnessi chì copre CRM, paghe è analitiche - a rigorosità di pyright cattura sottili discordanza di l'interfaccia chì l'inferenza indulgente mancassi.

Pytype è Pyre: E Strade Meno Viaggiate

U pytype di Google piglia forse l'approcciu più pragmaticu. Invece di esigene annotazioni o riturnà à Qualsiasi, pytype usa analisi di u prugramma tutaleper seguità cumu si usa un cuntinuu attraversu e fruntiere di e funzioni. Se crea una lista viota in una funzione è trasmette à un altru chì aghjunghjenu interi, pytype pò spessu inferisce list[int]senza alcuna annotazioni in tuttu. Questa inferenza di funzioni trasversali hè un calculu caru - pytype hè significativamente più lento di mypy o pyright in basi di codice grande - ma pruduce menu falsi pusitivi nantu à u codice senza annotazione.

Pytype introduce ancu u cuncettu di "tipi parziali" per i cuntenituri vacanti. Un [] appena creatu riceve un tipu parziale chì hè progressivamente raffinatu cum'è u verificatore scontra più usu. Questu hè cuncettualmente eleganti, ma pò pruduce missaghji d'errore confusi quandu u tipu parziale ùn pò micca esse risoltu cumplettamente, cum'è quandu un containeru viotu scorri attraversu parechje funzioni senza mai esse populatu.

💡 DID YOU KNOW?

Mewayz replaces 8+ business tools in one platform

CRM · Invoicing · HR · Projects · Booking · eCommerce · POS · Analytics. Free forever plan available.

Start Free →

U pira di Meta, intantu, hè più vicinu à u cumpurtamentu di mypy, ma cù predefiniti più stretti. Pyre tratta x = [] cum'è lista [sconnustu] è richiede annotazione in a maiò parte di i cuntesti. Induve pyre si distingue hè in a so gestione di literali di dizziunariu vacanti utilizati cum'è kwargs - un mudellu cumuni in frameworks web. Pyre hà una logica di casu speciale per inferisce i tipi di dizziunariu da i cuntesti di l'argumentu di keyword, riducendu a carica di annotazione in basi di codice pesante di framework. Siccomu a maiò parte di l'applicazioni web muderni implicanu un usu pesante di u dizziunariu per a cunfigurazione è a gestione di e dumande, stu pragmatismu rende dividendi.

Impattu in u mondu reale: quandu a divergenza di inferenza morde

E differenze trà i verificatori di tippu pò parenu accademicu finu à chì l'avete sperienze in una basa di codice di produzzione. Cunsiderate un mudellu cumuni in l'applicazioni cummerciale: inizializza una struttura di dati chì hè populata in cundizzioni.

I cuntenituri vioti più periculosi ùn sò micca quelli chì tippu checkers flag - sò quelli chì passanu in silenziu cù un inferitu Qualsiasi tippu, chì permette à e dati incompatibili di accumulà senza avvisu finu à chì una funzione downstream crashes in runtime cun un TypeError chì hè quasi impussibile di rintraccià a so origine.

Un esempiu concretu: una squadra in una startup fintech hà dichjaratu chì hà spesu trè ghjorni per debugging un prublema di produzzione induve una lista viota, inizializzata in una funzione di trattamentu di pagamentu, hè stata inferita cum'è list[Any]da mypy. A lista duvia cuntene uggetti Decimaliper quantità di valuta, ma un percorsu di codice era appiccicatu invece valori float. L'inferenza indulgente di Mypy l'hà permessu in silenziu. U bug hè apparsu solu quandu l'errore di arrotondamentu in l'aritmetica float hà causatu una discrepanza di $ 0,01 in un batch di fatture 12,000. S'elli avianu usatu pyright in modu strettu, o simpricimenti annotatu a lista viota cum'è list[Decimal], u bug saria statu catturatu in u tempu di sviluppu.

In Mewayz, induve a piattaforma processa a fatturazione, i calculi di paghe è l'analitiche finanziarie in più di 138.000 cunti d'utilizatori, stu tipu di divariu di sicurezza di tipu ùn hè micca teoricu - hè a diffarenza trà curretti curretti di paghe è ricalculi costosi. A rigorosa disciplina di digitazione intornu à l'inizializazione di u containeru hè una di quelle pratiche di ingegneria "noiosa" chì impedisce incidenti di produzzione eccitanti.

Best Practices for Defensive Container Initialization

Indipendentemente da quale verificatore di tipu usa a vostra squadra, ci sò strategie concrete per eliminà l'ambiguità di u containeru viotu sanu. L'obiettivu hè di ùn mai cunfidassi di l'inferenza per i cuntenituri vioti - rende u tipu esplicitu cusì u vostru codice hè portabile in tutti i checkers è immune à i cambiamenti di cumpurtamentu di inferenza trà e versioni.

  1. Annutate sempre e variabili di u containeru viotu. Scrivite results: list[int] = [] invece di results = []. U costu di verbosità minore hè insignificante cumparatu cù u tempu di debugging salvatu. Questa pratica unica elimina circa 80% di i prublemi di inferenza di u containeru vacanti.
  2. Utilizà funzioni di fabbrica per cuntenituri cumplessi. Invece di cache = {}, scrivite una funzione cum'è def make_cache() -> dict[str, list[UserRecord]]: return {}. L'annotazione di u tipu di ritornu rende u tipu intesu unambiguu è auto-documentatu.
  3. Preferite i custruttori tipati à i litterali per i tipi non triviali. Scrivite items: set[int] = set() piuttostu cà di confià à l'inferenza di cumpressione di set. Per defaultdict è Counter, furnite sempre u paràmetru di tipu: counts: Counter[str] = Counter().
  4. Configurate u modu strettu di u vostru verificatore di tipu per u novu codice. Sia mypy è pyright supportanu a cunfigurazione per file o per directory. Abilita u cuntrollu strettu di novi moduli mentre migrate gradualmente u codice legacy. Questu impedisce l'accumulazione di novi cuntenituri implicitamente tipati.
  5. Aggiungi un paragone di verificatore di tipu à a vostra pipeline CI. Eseguisce sia mypy sia pyright in a vostra basa di codice rileva a divergenza di inferenza prima. Se un mudellu passa un verificatore ma falla un altru, hè un signalu chì u tipu ùn hè micca abbastanza esplicitu.

U Bigger Picture: Type Checking as a Team Practice

L'inferenza di u containeru viotu hè in ultimamente un microcosmu di una sfida più grande in u sistema di tipu di Python: a tensione trà comodità è sicurità. A filusufìa di Python di "semu tutti l'adulti accunsentanti" funziona bè per i prototipi è i script, ma i sistemi di produzzione chì servenu migliaia d'utilizatori necessitanu garanzii più forti. U fattu chì quattru verificatori di tipu maiò ùn sò micca d'accordu annantu à qualcosa di basi cum'è u tipu di [] sottolinea chì l'ecosistema di scrittura di Python hè sempre maturu.

Per i squadre di ingegneria chì custruiscenu piattaforme cumplesse - sia gestite una manciata di microservizi o un sistema integratu cù centinaie di moduli interconnessi cum'è l'OS di l'impresa di Mewayz - i cunsiglii pratichi sò diretti: ùn vi fidate micca di l'inferenza per i cuntenituri vacanti, sceglite un verificatore di tipu è cunfigurate strettu, è trattate l'annotazioni di tipu cum'è documentazione chì hè verificata in una macchina. I cinque minuti passati à scrive lista[Fattura] invece di [] vi risparmieranu ore di debugging quandu u vostru codice base scala.

Siccomu PEP 696 (parametri di tipu predefinitu) è PEP 695 (sintassi di parametru di tipu) cuntinueghjanu à sbarcà in e versioni più recenti di Python, l'ergonomia di a digitazione esplicita continuarà à migliurà. U distaccu trà "annotated" è "unannotated" Python si restringerà. Ma finu à quellu ghjornu, i tipi di cuntenituri espliciti restanu una di e pratiche più altu ROI in u toolkit di sviluppatore Python - una piccula disciplina chì paga interessu cumpostu in ogni modulu, ogni sprint, è ogni implementazione di produzzione.

Custruisce u vostru sistema operativu cummerciale oghje

Da i freelancers à l'agenzii, Mewayz alimenta più di 138.000 imprese cù 207 moduli integrati. Cumincià gratis, aghjurnà quandu cresce.

Crea un contu gratuitu →

Domande Frequenti

Perchè i verificatori di tipu ùn ponu micca accordu nantu à u tipu di una lista viota ?

Quandu scrive `x = []`, u verificatore di tipu deve inferisce un tipu senza suggerimenti espliciti. Diversi verificatori utilizanu diverse strategie: alcuni inferiscenu `list[Any]` (una lista di qualcosa), mentri àutri ponu inferisce un tipu più specificu ma sbagliatu cum'è `list[None]`. Questa mancanza di un standard universale hè per quessa ch'elli ùn sò d'accordu. Per i prughjetti chì utilizanu più checkers, sta incongruenza pò esse un malu di testa maiò, rompe l'analisi in un strumentu chì passa in un altru.

Quale hè u modu più simplice per riparà l'errori di u containeru viotu ?

A suluzione più simplice hè di furnisce una annotazione di tipu esplicitu. Invece di `my_list = []`, scrive `my_list: list[str] = []` per dichjarà esplicitamente u tipu previstu. Questu elimina tutte l'ambiguità per u verificatore di tipu, assicurendu un cumpurtamentu coherente in diverse strumenti cum'è mypy, Pyright è Pyre. Questa pratica hè cunsigliata per tutte l'inizializazione di u containeru viotu per prevene l'errore di inferenza.

Cumu possu trattà cuntenituri vacanti in definizioni di classi?

Questu hè un prublema cumuni perchè l'annotazioni in e classi necessitanu un trattamentu speciale. Duvete aduprà l'importazione "da __future__ annotations d'importazione" o una annotazione "ClassVar" se a lista hè destinata à esse un attributu di classa. Per esempiu, `class MyClass: my_list: ClassVar[list[str]] = []`. Senza questu, u verificatore di tippu pò avè difficultà per inferisce currettamente u tipu, purtendu à errori.

Ci sò arnesi per aiutà à gestisce questi prublemi di scrittura in grandi prughjetti ?

Iè, i verificatori di tipu avanzatu cum'è Pyright (chì alimenta Pylance in VS Code) sò particularmente boni per trattà l'inferenza cumplessa. Per i grandi codebases, piattaforme cum'è Mewayz (offre 207 moduli di analisi per $ 19 / mese) ponu furnisce una verificazione di tipu più profonda è più consistente è aiutanu à rinfurzà e pratiche di annotazione in tutta a vostra squadra, mitigando l'inconsistenze discusse in l'articulu.

Try Mewayz Free

All-in-one platform for CRM, invoicing, projects, HR & more. No credit card required.

Start managing your business smarter today

Join 30,000+ businesses. Free forever plan · No credit card required.

Ready to put this into practice?

Join 30,000+ businesses using Mewayz. Free forever plan — no credit card required.

Start Free Trial →

Ready to take action?

Start your free Mewayz trial today

All-in-one business platform. No credit card required.

Start Free →

14-day free trial · No credit card · Cancel anytime