Comparação entre os dois novos type checkers de Python baseados em Rust: Pyrefly e Ty
(blog.edward-li.com)- Recentemente, foram apresentados dois type checkers de Python baseados em Rust — Pyrefly, da Meta, e Ty, da Astral — mostrando desempenho avassalador e um novo paradigma de tipagem em relação a mypy e pyright
- O Pyrefly busca inferência de tipos agressiva e foco em open source, enquanto o Ty introduz o princípio da “gradual guarantee”, com ênfase em minimizar a ocorrência de erros de tipo
- Embora ambos ainda estejam em versões alfa iniciais, benchmarks em vários projetos mostraram que o Ty registra, em média, velocidade de execução maior
- Em análise incremental, o Pyrefly opera por módulo, enquanto o Ty oferece granularidade fina no nível de função, o que resulta em diferenças de uso e estrutura
- O Ty apresenta um sistema de tipos inovador, com intersection types e negation types, além de mensagens de erro mais intuitivas e claras
Introdução ao Pyrefly e ao Ty
- Pyrefly e Ty são type checkers de Python desenvolvidos em Rust
- O Pyrefly foi desenvolvido pela Meta (antigo Facebook) e substitui o Pyre, que era baseado em OCaml
- O Ty foi desenvolvido pela Astral, conhecida por ferramentas Python como uv e ruff
- Ambos os projetos são open source, mas ainda estão em fase alfa antes do lançamento oficial
- As duas equipes apresentaram suas visões, metas e abordagens no PyCon 2025 Typing Summit
Semelhanças
- Ambos foram desenvolvidos em Rust e oferecem suporte a análise incremental (Incremental Checking)
- Usam o ruff para o parsing de AST do código Python
- Também se destacam pela boa integração com o ambiente de desenvolvimento, incluindo verificação de tipos via linha de comando e integração com LSP/IDE
Diferença 1: velocidade
Benchmark do PyTorch
- O Ty é cerca de 2 a 3 vezes mais rápido que o Pyrefly, e ambos são de 10 a 20 vezes mais rápidos que mypy e pyright
- O Pyrefly mira um ganho de desempenho de 35 vezes em relação ao Pyre e de 14 vezes frente a mypy/pyright
- O Ty foi projetado com a meta de ser de uma a duas ordens de grandeza mais rápido que a geração atual de type checkers
Benchmark do Django
- O Ty foi o mais rápido, seguido pelo Pyrefly
- O Pyright apresentou resultados claramente mais lentos
Benchmark do repositório do mypy
- Resultado semelhante: o Ty foi o mais rápido, com o Pyrefly logo atrás por pequena margem
- mypy e pyright registraram tempos de execução significativamente mais lentos
Diferença 2: objetivo de tipagem
Pyrefly
- Adota uma estratégia de inferir tipos ao máximo, mesmo sem tipos explicitamente declarados no código, para capturar erros
- Busca maximizar a estabilidade do código por meio de uma inferência de tipos mais agressiva
Ty
- Aplica o princípio de gradual guarantee
- Foi projetado para que remover tipos explícitos de um código que funciona não passe a gerar erros de tipo
- Não provoca erros na ausência de type annotations e só exige anotações adicionais quando necessário
- Exemplo: mesmo ao atribuir um valor a um campo sem tipo explícito, não gera erro de tipo, tratando-o como
Unknown | None, entre outros casos
Diferença 3: forma de análise incremental
- Pyrefly: reanalisa apenas os arquivos alterados (módulos) e os módulos dependentes correspondentes (incremental por módulo)
- Ty: usa o framework Salsa, do Rust, para uma incrementalização mais detalhada, chegando ao nível de função
- A abordagem por módulo parte da premissa de que a velocidade já é suficiente; a abordagem por função pode tornar a base de código mais complexa (diferença de estratégia entre as ferramentas)
Diferença 4: funcionalidades (sistema de tipos e suporte)
Pontos fortes do Pyrefly
- A inferência implícita de tipos é muito poderosa
- Mesmo sem tipos explícitos, analisa tipos complexos como retornos de função, dicionários e listas para detectar erros
- Foi projetado com foco em problemas complexos de tipagem, como generics, overloads e wildcard imports
- A precisão da inferência de tipos genéricos é superior à do Ty
Particularidades do Ty
- Graças à “gradual guarantee”, permite mudanças de tipo com mais liberdade mesmo quando faltam tipos explícitos
- Oferece suporte a sistemas de tipos inovadores, como intersection types e negation types
- As mensagens de erro foram desenhadas para ser muito claras e intuitivas
- Permite com liberdade a atribuição de diferentes tipos em listas e introduz sistematicamente o valor de tipo
Unknown
Limitações / estado alfa
- Ambos ainda estão em fase alfa, com partes da inferência de tipos e de algumas funcionalidades ainda incompletas
- Por exemplo, alguns resultados do Ty, como a inferência de tipo de listas, ainda não têm acabamento ideal
Comparação detalhada de recursos
Inferência implícita de tipos
- O Pyrefly infere ativamente tipos de retorno e de objetos de coleção, exibindo com clareza o tipo revelado e os erros
- O Ty retorna
Unknownou@Todoquando a inferência é insuficiente
Generics
- Tanto o Pyrefly quanto o Ty resolvem bem problemas comuns de tipos genéricos
- O Pyrefly leva vantagem na interpretação do tipo de instâncias criadas sem parâmetros de tipo
- Ambos mostram fraquezas em questões de covariância/contravariância (covariance/contravariance) em comparação com mypy e pyright
Mensagens de erro
- O Ty prioriza mensagens de erro concisas e fáceis de ler
- Em comparação com Pyrefly, mypy e pyright, oferece mensagens mais fáceis de entender de imediato
Intersection / negation types
-
Apenas o Ty oferece suporte a intersection types (
&) e negation types (~), tratando operações de tipo complexas como as abaixo- Exemplo: em um tipo
WithX | Other, quando existe o atributox, o Ty faz automaticamente o branch paraWithX - Exemplo: ao excluir uma subclasse específica, interpreta o tipo como
MyClass & ~MySubclass
- Exemplo: em um tipo
-
Esses intersection e negation types são recursos bastante avançados na teoria dos tipos
Outros exemplos avançados
- O Ty pode até ser usado, via sistema de tipos, em operações complexas como equações diofantinas
- Os testes são escritos em documentos Markdown (referência: recurso mdtest do ruff da Astral)
Conclusão e perspectivas
- O ecossistema Python passa a contar com novos type checkers extremamente rápidos e com abordagens inéditas
- O Ty adota como estratégia principal a estabilidade gradual de tipos, enquanto o Pyrefly aposta na inferência ativa de tipos
- Como ambos ainda estão no início, há bastante espaço para convergência ou evolução de funcionalidades no futuro
- Já é possível testá-los nos sites oficiais, e há também plugins para editores importantes como VSCode e Cursor
- Também há rumores de que o Google pretende open-sourcear um type checker baseado em Go, o que pode tornar a área de análise de tipos em Python ainda mais rica
Uso / referência
- Pyrefly: pyrefly.org/sandbox
- Ty: play.ty.dev
- O Ty da Astral usa testes baseados em Markdown (para o caminho detalhado, consulte o mdtest no repositório do ruff)
- A documentação oficial, plugins de editor e comandos de instalação de pacote também já estão disponíveis
2 comentários
Parece que o
tytrata comounknownsempre que o tipo de retorno não é especificado na função; ele só verifica depois de salvarJá o
pyreflyconsegue inferir mesmo sem isso, e verifica até durante a digitação.Comentários do Hacker News
Como desenvolvedor do ty, ressalto que fico feliz em ver ty e pyrefly recebendo cada vez mais atenção, mas reforço mais uma vez que ambos os projetos ainda não estão prontos. Também vemos exemplos causados por funcionalidades ainda não implementadas, então, quando algo parecer “isso está estranho”, peço que considerem que talvez seja simplesmente uma parte que ainda não foi desenvolvida. Também é preciso reconhecer que Python é uma linguagem enorme e muito diversa.
Acho muito legal o jeito como o ty faz testes em estilo markdown; é uma ótima ideia que os testes também sirvam como documentação. Fico curioso se essa abordagem foi inspirada pelos exemplos de código documentados do Rust.
Ri ao ver partes que expõem tipos marcadas como
@TODO, mas pensando melhor, achei um recurso bem esperto e útil.Como alguém com experiência em TypeScript, acho interessante a variedade de tentativas, como inferência de tipos, narrowing de tipos e o fato de cada type checker de Python se comportar de forma diferente. Ainda assim, faz muita falta um type checker rápido e confiável, e tenho a sensação de que Python está bem atrás nisso. Acho que type checkers deveriam aumentar a produtividade e a confiabilidade do código, então torço por projetos assim.
Do ponto de vista de um desenvolvedor Rust, surge a pergunta sobre uma “linguagem de script para Rust”: existe alguma comunidade pesquisando uma linguagem que combine bem com a sintaxe de Rust, permita importar tipos de Rust nativamente e compile rápido/com hot reload? E, mesmo que a sintaxe seja diferente, será que Python poderia cumprir esse papel? Link relacionado: https://news.ycombinator.com/item?id=44050222
Opinião de alguém de fora, sem muita experiência com Python: se você se interessa por usar type hints, recomendo ver este post do Reddit https://www.reddit.com/r/Python/comments/10zdidm/why_type_hinting_sucks/. Não é para levar o texto ao pé da letra, mas o ponto é que, por melhores que sejam as ferramentas de tipos, “boas práticas” vêm primeiro. Por exemplo, para possibilitar uso consistente e checagem rígida de tipos em codebases grandes como as do Django ou da Meta, é preciso fazer com que os desenvolvedores sigam as convenções recomendadas. Python, assim como C++, tem recursos demais e um runtime permissivo demais, então no fim fica mais fácil manter tudo sob controle usando apenas uma parte limitada da linguagem. O problema é que essa parte limitada pode variar conforme a pessoa e o objetivo. Isso também foi comparado aos casos em que desenvolvedores Rust entram em choque com mantenedores do kernel Linux por conta de um sistema de tipos mais rígido.
Em um dos comentários mais votados desse post do Reddit, a questão é descartada com algo como “é só usar
Any, então a discussão não faz sentido”. Mas, em casos reais, declarações de tipo mais explícitas poderiam evitar erros com mudanças futuras em funções de bibliotecas ou com entradas inesperadas. Afirmo com bastante convicção que, para código Python ser sustentável e confiável, type checking é essencial.Em vez de gastar tempo e esforço demais com type checking em Python, talvez seja melhor migrar logo para uma linguagem estaticamente tipada mais adequada e usar Python só onde for necessário, por meio de uma camada de interop. Nem sempre isso é possível, claro, mas há a preocupação de que se desperdice muito tempo tentando forçar Python a se encaixar.
Crítica aos recursos poderosos e complexos do Python (por exemplo: meta class, descriptor, uso de
__call__,object.__new__, name mangling,self.__dict__): há magia demais nisso tudo, e isso prejudica bastante a legibilidade do código. Pessoalmente, declaro que não pretendo usar esses recursos.Fico curioso sobre de onde vem a motivação para opinar sem de fato usar a linguagem. Desenvolvedores Python a usam na prática e a entendem profundamente, então é estranho ver alguém de fora criticando a linguagem com base em fundamentos externos. Também foi apontado um clima de discussão baseado em contrived example (exemplos forçados).
Como alguém que usa Python há muitos anos, afirmo que o maior erro é simplesmente não usar type hints nem type checker.
Achei interessante a “garantia gradual” do ty, isto é, a ideia de que remover uma anotação de tipo não deveria provocar erro de tipo. Parece a abordagem mais adequada para Python, que tem muito código dinâmico.
Tipagem gradual é uma estrutura em que pode haver “any” (tipo indefinido) em qualquer parte do código sem nem mesmo um aviso. Lembro que isso causava o problema de nem mesmo partes importantes do código terem garantia total de segurança de tipos e, portanto, não ficarem realmente protegidas. Na minha experiência com mypy, isso era fatal, e considero indispensável algum recurso para declarar “este arquivo será checado com tipagem totalmente estática”. Na minha opinião, tipagem “gradual” chega a ser um anti-pattern; talvez o termo “soft typing” fosse até mais apropriado.
Em codebases existentes, não há muito caminho além da tipagem gradual. Pela minha experiência aplicando type hints com mypy em vários codebases legados em Python, o mais razoável é um opt-in por módulo. Se o pyrefly não suportar isso, talvez seu uso prático fique limitado. Por outro lado, no contexto de geração de código com llm (grandes modelos de linguagem), um type checker muito rápido e rígido pode ser bastante útil.
Isso lembra a adoção inicial do TypeScript: o foco é permitir uma entrada suave em projetos grandes já existentes. Aos poucos, você ativa opções como
noImplicitAnyoustrictpor módulo e, no fim, converte o ambiente para uma validação de tipos forte.Mesmo como programador Rust, acho que a “garantia gradual” é a mais razoável.
Pessoalmente, esse tipo de suporte a tipagem gradual não me atrai muito. O próprio sistema de tipos dinâmicos do Python já é instável, então metade do objetivo de adicionar anotações de tipo é justamente controlar esse mau funcionamento. Por isso, gostaria muito que houvesse opções como no-implicit-any ou modo strict.
As ferramentas da Astral trouxeram energia nova ao ecossistema Python, mas surgiu uma dúvida sobre a “visão de longo prazo”: isso vai acabar sendo integrado diretamente ao Python? Vai desaparecer em cinco anos? Vai virar um rug pull por assinatura?
Por meio de uma Business Source License, há uma boa chance de tentarem tornar obrigatórias coisas como assinaturas corporativas para deploys em produção que usem ferramentas da Astral. O produto atual não é exatamente isso, mas, do ponto de vista de retorno para venture capital, um modelo parecido parece provável.
No anúncio oficial, a Astral deixou claro que venderá vários serviços em cima das ferramentas. Link de referência: https://astral.sh/blog/announcing-astral-the-company-behind-ruff
Na verdade, essa preocupação não vale só para a Astral, mas para todos os projetos. E, especialmente no caso de ferramentas do Facebook, há um risco grande de abandono com o tempo. No fim, o usuário sempre precisa assumir esse risco por conta própria.
Citação da opinião de um usuário do Reddit: o modelo básico de VC costuma ser esperar aquisição por uma FAANG (big tech) ou crescer de forma agressiva para buscar um “acqui-hire”. A Astral também poderia seguir um caminho de fusão e aquisição com absorção de talentos.
Há rumores recentes de que a Astral também está preparando ferramentas voltadas a grandes empresas, como um private package registry hospedado.
No exemplo
my_list = [1, 2, 3], mypy, pyrefly e pyright tratammy_list.append("foo")como erro de tipo, mas só o ty permite isso sem nenhuma indicação adicional. Houve a crítica forte de que, no trabalho real, o normal é usar listas de tipo único, então o type checker deveria partir desse princípio. Só porque Python permite isso não significa que a validação de tipos deva ser frouxa; houve até a opinião de que isso parece uma política otimizada para iniciantes.Como desenvolvedor do ty, explico que “a inferência de tipos para literais de lista ainda não está pronta”. No momento, usamos apenas
list[Unknown], eUnknowné um tipo gradual parecido comAny, então qualquerappendacaba sendo permitido. Há planos de fazer inferência mais precisa no futuro, e foi incluído o link para a issue da discussão: https://github.com/astral-sh/ty/issues/168Houve a observação de que isso não é uma otimização para iniciantes, mas uma consequência inevitável de compatibilidade com código legado. Para introduzir um type checker em grandes codebases não tipados, o ideal é que o código existente continue funcionando quase como está, para reduzir a fricção.
Contra-argumento: “não convence querer fazer tooling com base em opinião pessoal, ignorando aquilo que o Python permite”.
Foi apontado um problema na abordagem do pyrefly: “em grandes codebases sem tipos, é difícil adotar de forma ampla”. Seria preciso ir corrigindo o código um por um, e isso se torna difícil se não houver consenso na organização para fazer esse trabalho. Em lugares como a Meta, onde isso pode ser imposto internamente, funciona melhor; mas, pensando em adoção gradual, uma abordagem mais permissiva como a do ty parece mais realista. Ainda assim, pessoalmente prefiro ferramentas que emitam warning para tipos mistos.
Houve também a opinião de que, “se o código Python é executável, então o correto é não haver erro de tipo, a menos que os tipos tenham sido explicitamente restringidos”. Se quiser um subconjunto estático mais rígido, a ideia é que você mesmo adicione anotações de tipo.
Houve a opinião de alguém com experiência de que a abordagem do Pyrefly, ao buscar inferência de tipos mais forte, exige muito menos anotações em código realmente type-safe em grande escala. Isso pode tornar a adoção inicial mais difícil, mas, no longo prazo, tende a ser mais eficiente. Já o ty, na prática, seria como usar
noImplicitAnydesativado.Existe expectativa por um type checker com suporte sério a integração com notebook (live coding), para pegar erros com análise estática antes de executar células longas — algo visto como um ganho enorme de eficiência.
Foi perguntado sobre a experiência de usar notebooks Jupyter no VSCode; houve a observação de que aplicar um type checker como o pylance pode até atrapalhar mais em código experimental.
Foi recomendada a experiência do Language Server do VSCode, que permite feedback imediato durante notebook integration e live coding, atendendo justamente a essa necessidade de type checking interativo.
A arquitetura do Pyrefly lembra a forma como o TypeScript faz inferência de tipos, e isso pareceu mais razoável para alguns. Também foi avaliado que uma adoção gradual (incremental) por módulo é o ideal; descer até o nível de função seria granular demais e além do necessário. Em termos de desempenho também parece suficiente ficar no nível de módulo.
Mesmo em projetos com muita dinamicidade, houve quem dissesse que ainda prefere inferência de tipos mais forte, como a do Pyrefly, e que aceitaria a inconveniência disso.
Atualmente, há quem use basedpyright em IDE e CI e esteja satisfeito com a estabilidade. Já o mypy não agrada por às vezes falhar até em tarefas simples de tipagem.