Trilha de aprendizado · Nível 12 · Tutorial 1

Verificar anotações com mypy

Executar o mypy em módulos anotados, interpretar seus diagnósticos e corrigir incompatibilidades sem desativar a verificação com Any.

  • Nível: Intermediário
  • Duração: 18 min
  • 7 passos
Verificar anotações com mypy

O que você vai percorrer

  1. Executar o mypy no ambiente correto Faça a primeira análise estática de um módulo local, confirmando o interpretador, a instalação do mypy e a versão-alvo. 2 min
  2. Distinguir tipos declarados e inferidos Veja como o mypy estabelece contratos para variáveis locais a partir de valores atribuídos ou de anotações explícitas. 2 min
  3. Localizar incompatibilidades nos diagnósticos Leia os diagnósticos do mypy, relacione cada código à operação apontada e corrija a origem da incompatibilidade. 3 min
  4. Investigar a inferência com reveal_type Consulte temporariamente o tipo estático que o mypy atribui a uma expressão e use essa informação para orientar uma correção. 2 min
  5. Comparar Any e object Entenda por que Any pode ocultar operações incompatíveis e como object preserva limites úteis de verificação. 3 min
  6. Ampliar a análise com --strict Compare a análise padrão e estrita do mypy e use anotações para expor contratos verificáveis. 3 min
  7. Aplicar o ciclo de verificação e correção Pratique o ciclo completo de análise, correção e nova verificação em um módulo curto, sem usar Any para esconder incompatibilidades. 4 min

O que você vai aprender

  • Executar o mypy sobre arquivos selecionados, alinhando a versão-alvo ao Python utilizado.
  • Localizar incompatibilidades de atribuição, argumentos e retornos a partir dos diagnósticos.
  • Inspecionar tipos inferidos e acrescentar anotações quando necessário.
  • Distinguir o efeito de Any do uso de object na verificação de operações.

Antes de começar

  • Documentar funções com docstrings e tipos simples
  • Criar ambientes virtuais com venv
  • Instalar pacotes com pip no ambiente correto

Passo 1 de 7

Executar o mypy no ambiente correto

Faça a primeira análise estática de um módulo local, confirmando o interpretador, a instalação do mypy e a versão-alvo.

Analisar não é executar

Duas verificações complementares

O mypy faz análise estática: examina anotações e usos do código sem executar o programa. Ele complementa testes e validações em tempo de execução; não os substitui.

Neste level, use Python 3.12 ou superior como referência. O mypy precisa estar instalado no mesmo ambiente Python em que você pretende analisar o projeto.

Dois fluxos, dois objetivos

Diagrama comparando a análise estática de um arquivo Python pelo mypy, sem executar suas instruções, com a execução normal do arquivo pelo interpretador Python.

mypy inspeciona contratos estáticos; python executa as instruções do módulo.

Dica

Use o mesmo Python

Prefira comandos iniciados por python -m. Assim, pip e mypy são chamados pelo interpretador ativo — especialmente importante dentro de um ambiente virtual.

Prepare o verificador

Confira e instale

No terminal, com seu ambiente virtual ativado se você usa um, confira a versão do Python. Se o mypy ainda não estiver disponível nesse ambiente, instale-o. Depois, confirme sua versão.

Comandos de preparação

Execute estes comandos no terminal, um por vez.

bash
python --version
python -m pip install mypy
python -m mypy --version

Atenção

Versão-alvo não troca o interpretador

A opção --python-version informa ao mypy qual versão de Python ele deve considerar ao analisar a sintaxe e as APIs. Ela não instala, não atualiza e não troca o Python que executa o comando.

Analise um módulo local

Crie `saudacao.py`

No seu computador, crie um arquivo chamado saudacao.py com o conteúdo abaixo. O módulo é curto e completo: ao ser executado, ele apenas mostra uma saudação.

saudacao.py

python
def montar_saudacao(nome: str) -> str:
    return f"Olá, {nome}!"


mensagem = montar_saudacao("Lia")
print(mensagem)

Analisar e executar são comandos diferentes

Na pasta que contém o arquivo, primeiro analise-o. Como o exemplo usa Python 3.12 como alvo, informe essa versão. Em seguida, se quiser observar o comportamento normal do programa, execute-o separadamente.

bash
python -m mypy --python-version 3.12 saudacao.py
python saudacao.py

Exemplo

Resultado esperado

A análise deve terminar sem erros, com uma mensagem semelhante a Success: no issues found .... Já python saudacao.py executa o módulo e imprime Olá, Lia!.

Se o seu python --version indicar outra versão suportada, alinhe o alvo: por exemplo, use --python-version 3.13 ao trabalhar com Python 3.13.

Escolha o comando correto

Primeira análise

Você está em um ambiente com Python 3.12 e quer analisar apenas saudacao.py. Qual comando atende a esse objetivo?

Registre sua primeira execução

O que o terminal informou?

Execute a análise do arquivo criado. Qual comando você usou e o que o mypy informou? Se houve um problema de ambiente, descreva-o brevemente.

Escreva pelo menos 20 caracteres (0/20).

Passo 2 de 7

Distinguir tipos declarados e inferidos

Veja como o mypy estabelece contratos para variáveis locais a partir de valores atribuídos ou de anotações explícitas.

De onde vem o tipo local?

Inferência em valores simples

Dentro de uma função com assinatura anotada, o mypy atribui tipos às variáveis locais a partir de expressões simples. Ao receber um número inteiro, uma variável passa a ter contrato de int; ao receber texto, de str; e ao receber uma comparação, de bool.

Fluxo da inferência

O valor da primeira atribuição estabelece o contrato estático da variável local.

Diagrama mostrando uma função com três valores simples levando às variáveis total como inteiro, mensagem como texto e aprovado como booleano.

Em atribuições simples, o mypy infere o tipo a partir da expressão atribuída.

Inferir ou declarar

Dois contratos equivalentes

Crie ou compare este exemplo em um arquivo Python e execute o mypy sobre ele.

python
def resumo(pontos: int, limite: int) -> str:
    # Tipos inferidos pelas expressões à direita:
    restantes = limite - pontos
    mensagem = "Meta alcançada"
    atingiu_meta = pontos >= limite

    # Os mesmos contratos, agora declarados explicitamente:
    restantes_declarados: int = limite - pontos
    mensagem_declarada: str = "Meta alcançada"
    atingiu_meta_declarado: bool = pontos >= limite

    return f"{mensagem}: faltam {restantes} pontos. Meta? {atingiu_meta}"

Exemplo

Quando anotar?

As duas formas são válidas. Use uma anotação local para tornar uma intenção importante explícita, especialmente se a expressão for pouco clara. Não repita anotações apenas porque o tipo já é evidente em uma expressão simples.

Dica

Contrato, não conversão

quantidade: int = "12" não transforma o texto em inteiro. A anotação declara o contrato esperado; o valor ainda precisa ser compatível com ele.

Reatribuir mantém o contrato

Uma reatribuição incompatível

Depois da primeira atribuição, a variável total continua sendo tratada como int.

python
def calcular_total(preco: int, desconto: int) -> int:
    total = preco - desconto
    total = "indisponível"  # incompatível com o contrato int
    return total

O que corrigir?

O diagnóstico aponta que um str foi atribuído onde o mypy esperava int. Preserve o contrato pretendido: forneça um inteiro a total ou reorganize o código para que uma variável de texto tenha outro nome e outra finalidade.

Pratique a anotação local

Complete o contrato

Complete a anotação coerente para este valor local:

<code>def pode_tentar(tentativas: int) -> bool:
disponivel: ____ = tentativas > 0
return disponivel</code>

Passo 3 de 7

Localizar incompatibilidades nos diagnósticos

Leia os diagnósticos do mypy, relacione cada código à operação apontada e corrija a origem da incompatibilidade.

Como ler uma mensagem do mypy

Da saída até a causa

Cada diagnóstico aponta um arquivo, uma linha, uma descrição e um código entre colchetes. Comece pela linha indicada, mas investigue também o contrato envolvido: a anotação da variável, do parâmetro ou do retorno.

Em mensagens como Expected "int", got "str", o primeiro tipo é o esperado naquele ponto; o segundo é o tipo do valor fornecido.

Anatomia de um diagnóstico

Use as partes da mensagem para seguir da localização até o contrato que foi violado.

Diagrama de uma saída de analisador estático mostrando arquivo e linha, descrição de tipos esperado e recebido, e código de categoria ligados aos trechos correspondentes de um módulo Python.

Arquivo e linha dizem onde observar; a descrição mostra o conflito; o código classifica a operação incompatível.

Três operações, três categorias

mismatch.py

Crie ou compare este módulo com a saída abaixo.

python
def dobrar(valor: int) -> int:
    return "2" * valor

quantidade: int = "3"
resultado = dobrar("4")
print(resultado)

Exemplo

Saída possível do mypy

mismatch.py:2: error: Incompatible return value type (got "str", expected "int")  [return-value]
mismatch.py:4: error: Incompatible types in assignment (expression has type "str", variable has type "int")  [assignment]
mismatch.py:5: error: Argument 1 to "dobrar" has incompatible type "str"; expected "int"  [arg-type]
  • [return-value]: a implementação devolve str, mas dobrar promete int.
  • [assignment]: a variável quantidade foi declarada como int, mas recebe str.
  • [arg-type]: a chamada passa str ao parâmetro valor: int.

A mesma linha pode depender de uma assinatura em outra linha. Por isso, siga o valor até sua origem e confira o contrato.

Associe o diagnóstico à operação

Categorias do mypy

Faça a correspondência entre cada código e a incompatibilidade que ele descreve.

Toque em um item e depois no par correspondente.

Corrija a causa, não o sintoma

Escolha a correção pela intenção

Não altere uma anotação apenas para fazer o diagnóstico desaparecer. Primeiro decida o comportamento pretendido:

  • Se a quantidade deve ser numérica, use valores int na atribuição e na chamada.
  • Se dobrar deve calcular o dobro, devolva uma expressão numérica.
  • Se a assinatura estava errada para o comportamento realmente desejado, ajuste-a de forma coerente com a implementação e com seus consumidores.

Depois, execute novamente python -m mypy mismatch.py para confirmar a compatibilidade.

Explique uma correção

No módulo mismatch.py, suponha que a intenção seja trabalhar somente com números inteiros e que dobrar(4) produza 8. Explique uma correção para os três diagnósticos.

Escreva pelo menos 80 caracteres (0/80).

Passo 4 de 7

Investigar a inferência com reveal_type

Consulte temporariamente o tipo estático que o mypy atribui a uma expressão e use essa informação para orientar uma correção.

Consultar o tipo visto pelo mypy

Uma pergunta ao verificador

Use reveal_type(expressão) para pedir ao mypy o tipo estático que ele atribuiu àquela expressão naquele ponto do código. É uma consulta: ela não altera o valor nem converte nada.

Coloque-a perto da variável ou chamada que você quer investigar. O mypy reconhece reveal_type nesse fluxo sem que você faça importação.

Fluxo da consulta

A chamada serve para comparar sua hipótese com a inferência do verificador.

Diagrama mostrando uma expressão em código apontando para o mypy, que devolve uma nota com o tipo inferido; em seguida, o programador decide corrigir a origem ou manter o código.

reveal_type produz uma nota informativa para apoiar sua decisão.

Ver uma nota, não um erro

Módulo para investigar

Crie um arquivo chamado tipos_revelados.py com este conteúdo:

python
def formatar_codigo(numero: int) -> str:
    return f"COD-{numero:03d}"

quantidade = 7
codigo = formatar_codigo(quantidade)

reveal_type(quantidade)
reveal_type(codigo)

print(codigo)

Execute a análise

No ambiente em que instalou o mypy, execute:

python -m mypy --python-version 3.12 tipos_revelados.py

A saída deve trazer notas equivalentes a Revealed type is "builtins.int" e Revealed type is "builtins.str". Essas notas descrevem a inferência; não são diagnósticos de incompatibilidade como assignment, arg-type ou return-value.

Preveja a segunda nota

Antes de analisar: reveal_type(codigo) informará builtins.___.

Interpretar e remover a instrumentação

Atenção

Não execute o arquivo com as consultas

reveal_type é reconhecido pelo mypy, mas não existe automaticamente para a execução normal do Python neste fluxo. Antes de rodar python tipos_revelados.py, remova ou comente todas as chamadas a reveal_type.

Use a resposta para decidir

Se o tipo revelado coincidir com sua intenção, a anotação ou inferência já é suficiente. Se divergir, investigue a origem do valor e corrija-a, ou acrescente uma anotação quando ela expressar um contrato necessário. A nota não corrige o código por você: ela mostra o que o mypy concluiu.

Prática local

No seu computador, execute o mypy no arquivo apresentado. Qual tipo você previu para codigo, qual nota apareceu e o que você deve fazer com as chamadas a reveal_type antes de executar o módulo?

Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 7

Comparar Any e object

Entenda por que Any pode ocultar operações incompatíveis e como object preserva limites úteis de verificação.

Dois contratos muito diferentes

Any flexibiliza; object limita operações

Os dois tipos podem receber valores de tipos variados, mas produzem verificações bem diferentes.

  • Any, importado de typing, é um escape da análise estática: o mypy aceita atribuições, chamadas e acessos feitos a esse valor sem confirmar se são válidos.
  • object também aceita qualquer valor Python, mas representa apenas o contrato comum a todos os objetos. Por isso, o mypy permite somente operações garantidas para object.

Quando uma função precisa de uma operação específica de texto, como .upper(), o melhor contrato é str, não Any nem object.

O que cada anotação informa ao mypy

Diagrama comparando três parâmetros: str permite uma operação de maiúsculas; Any deixa a operação passar sem checagem; object bloqueia a operação específica e permite apenas operações gerais.

Any desliga a confirmação da operação; object mantém apenas o que todo objeto garante.

A mesma operação, diagnósticos diferentes

Compare os parâmetros

Salve como any_object.py e execute: python -m mypy --python-version 3.12 any_object.py

python
from typing import Any


def maiusculas_sem_checar(valor: Any) -> str:
    return valor.upper()


def maiusculas_com_contrato(valor: object) -> str:
    return valor.upper()


def descrever(valor: object) -> str:
    return str(valor)


print(maiusculas_sem_checar(42))
print(descrever(42))

Exemplo

Como interpretar o resultado

O mypy aceita maiusculas_sem_checar: como valor é Any, ele não confirma se .upper() existe. Também aceita a chamada com 42, mas a execução normal falhará com AttributeError.

Já em maiusculas_com_contrato, o mypy deve apontar que object não possui o atributo upper. Esse diagnóstico é útil: o contrato não garante a operação. Em contraste, str(valor) é permitido, pois produzir uma representação textual é uma operação geral válida para object.

Dica

Any também se propaga

O resultado de uma operação sobre Any tende a continuar sendo Any. Assim, uma informação pouco precisa pode se espalhar pelo código e reduzir as verificações posteriores. A ausência de diagnóstico com Any não comprova que a operação funcionará em tempo de execução.

Escolha o contrato que a implementação exige

Verifique a afirmação

Anotar um parâmetro como object permite chamar .upper() nele, pois todo valor Python é um objeto.

Decida pela assinatura

Uma função precisa remover espaços com .strip() e converter um nome para maiúsculas com .upper(). Qual contrato você escolheria para seu parâmetro: str, object ou Any? Justifique com base nas operações usadas.

Escreva pelo menos 50 caracteres (0/50).

Passo 6 de 7

Ampliar a análise com --strict

Compare a análise padrão e estrita do mypy e use anotações para expor contratos verificáveis.

O que muda no modo estrito

Análise padrão e análise estrita

No modo padrão, o mypy normalmente não verifica as operações dentro de uma função que não tem anotações. Isso evita diagnósticos em código ainda não tipado, mas também pode esconder incompatibilidades.

A opção --strict ativa um conjunto de verificações mais exigentes. Entre outros efeitos, ela cobra anotações em funções e torna mais visíveis trechos que o mypy não consegue verificar bem. O conjunto exato de opções pode variar entre versões do mypy.

Dois níveis de análise

A mesma operação pode passar despercebida no modo padrão e ficar verificável quando o contrato da função é declarado.

Diagrama comparando uma função sem anotações, pouco inspecionada no modo padrão, com uma função anotada analisada em detalhe no modo estrito.

Sem contrato anotado, há menos informação para o mypy checar; com contrato explícito, ele pode comparar argumentos, operações e retorno.

Experimente no seu módulo

Crie um exemplo local

No seu editor, crie um arquivo chamado rigor.py com este conteúdo. A função recebe um texto, mas tenta somá-lo a um número.

rigor.py

python
def dobrar(valor):
    return valor + 2

resultado = dobrar("10")
print(resultado)

Compare os comandos

No terminal do ambiente em que o mypy está instalado, execute os dois comandos sobre o mesmo arquivo. Troque 3.12 pela versão-alvo que você já está usando, se necessário.

bash
python -m mypy --python-version 3.12 rigor.py
python -m mypy --python-version 3.12 --strict rigor.py

Dica

Leia a diferença

É comum que a primeira análise não reporte a soma incompatível: a função não anotada é tratada de forma dinâmica. Com --strict, espere diagnósticos sobre a ausência de anotações. O objetivo é revelar que falta um contrato; não é apenas adicionar opções para silenciar a saída.

Torne o contrato verificável

Anote de acordo com a intenção

Se dobrar foi criada para números inteiros, declare isso no parâmetro e no retorno. Agora a chamada com "10" contradiz o contrato e o mypy consegue apontar a causa com um diagnóstico de argumento.

Versão anotada

python
def dobrar(valor: int) -> int:
    return valor + 2

resultado = dobrar("10")
print(resultado)

Interprete a correção

Para preservar a intenção de dobrar um inteiro, qual parte do código você corrigiria depois de adicionar as anotações? Explique em uma frase.

Escreva pelo menos 30 caracteres (0/30).

Rigor tem limites

Escolha a afirmação correta

Qual afirmação descreve corretamente o uso de --strict?

Atenção

Não confunda ausência de diagnósticos com garantia total

Mesmo com --strict, um Any explícito pode continuar permitindo operações não verificadas. Além disso, o mypy só analisa os arquivos e caminhos incluídos no comando. Execute os testes e mantenha validações para dados recebidos em tempo de execução.

Passo 7 de 7

Aplicar o ciclo de verificação e correção

Pratique o ciclo completo de análise, correção e nova verificação em um módulo curto, sem usar Any para esconder incompatibilidades.

Prepare um módulo para investigar

Do diagnóstico ao código corrigido

Agora você vai aplicar o ciclo completo: executar o mypy, relacionar cada mensagem à sua origem, confirmar uma inferência quando ela ajudar, corrigir o contrato ou o valor e analisar novamente.

No seu ambiente virtual, crie um arquivo chamado pedido.py com o código abaixo. Ele foi feito para conter incompatibilidades reais e uma anotação Any que deixa uma operação escapar da análise.

pedido.py — versão inicial

python
from typing import Any


def desconto(preco: float, percentual: float):
    return preco * (1 - percentual / 100)


def rotulo(codigo: Any) -> str:
    return codigo.upper()


def resumo() -> str:
    preco: float = "19.90"
    valor = desconto(preco, "10")
    return valor


print(resumo())

Ciclo de verificação

Diagrama em ciclo mostrando: conferir ambiente e versão-alvo, analisar com mypy, localizar o diagnóstico no código, corrigir, analisar novamente e executar o programa.

A análise estática orienta a correção; a execução normal confirma o comportamento com uma entrada concreta.

Dica

Use o mesmo interpretador

Confira o interpretador e o verificador do ambiente ativo antes de começar. A opção --python-version informa ao mypy qual versão-alvo considerar; ela não instala nem troca o Python.

Analise e rastreie as causas

Comandos de análise

Execute estes comandos no diretório que contém pedido.py. Ajuste 3.12 se o seu interpretador for outra versão compatível usada no projeto.

bash
python --version
python -m mypy --version
python -m mypy --python-version 3.12 pedido.py

O que procurar nos diagnósticos

Relacione cada mensagem à linha indicada, não apenas ao texto do erro:

  • preco: float = "19.90" é uma incompatibilidade de atribuição: o contrato declara float, mas o valor é str.
  • desconto(preco, "10") passa str onde o parâmetro exige float: incompatibilidade de argumento.
  • return valor devolve um float, embora resumo prometa str: incompatibilidade de retorno.

Além disso, desconto ainda não declara seu tipo de retorno. Isso se torna uma exigência na análise estrita. Já rotulo aceita Any, então codigo.upper() não é verificado de forma útil: se alguém passasse um número, a falha apareceria só na execução.

Consulta temporária de inferência

Se quiser confirmar sua hipótese sobre valor, acrescente temporariamente esta linha logo após sua atribuição e rode o mypy outra vez.

python
reveal_type(valor)  # mypy informa: Revealed type is "builtins.float"

Atenção

Remova antes de executar

reveal_type é entendido pelo mypy neste fluxo, mas não é uma chamada normal pronta para a execução do programa. Remova-a antes de rodar python pedido.py.

Corrija os contratos, não os esconda

Uma correção coerente

A intenção deste módulo é calcular um desconto e apresentar um texto. Portanto, use valores numéricos para preço e percentual, declare o retorno de desconto e exija str de quem chama rotulo. Assim, a operação .upper() passa a ter um contrato que a justifica.

pedido.py — versão corrigida

python
def desconto(preco: float, percentual: float) -> float:
    return preco * (1 - percentual / 100)


def rotulo(codigo: str) -> str:
    return codigo.upper()


def resumo() -> str:
    preco: float = 19.90
    percentual: float = 10.0
    valor = desconto(preco, percentual)
    return f"{rotulo('promo')}: R$ {valor:.2f}"


print(resumo())

Ordene o ciclo de trabalho

Organize as ações em uma sequência de verificação e correção responsável.

  1. Analisar o arquivo e localizar a origem de cada diagnóstico
  2. Corrigir valores, chamadas e anotações conforme o contrato
  3. Conferir o ambiente e definir a versão-alvo do mypy
  4. Usar reveal_type temporariamente se a inferência estiver em dúvida
  5. Analisar novamente com --strict e executar o programa

Confirme, execute e faça a revisão final

Verificação final

Com a versão corrigida salva e sem reveal_type, execute a análise estrita e depois o módulo.

bash
python -m mypy --python-version 3.12 --strict pedido.py
python pedido.py

Exemplo

Resultado esperado

O mypy deve terminar sem diagnósticos para esse arquivo. A execução deve mostrar:

PROMO: R$ 17.91

A ausência de erros do mypy é evidência de compatibilidade estática no arquivo e nas opções analisadas. Ela não substitui testes nem validações de dados que chegam de fora do programa.

Registro da sua verificação

Relate: o comando de análise usado, as correções que você fez, o resultado de --strict, o que observou ao executar e uma limitação do que essa verificação comprova.

Escreva pelo menos 120 caracteres (0/120).

Resumo

Síntese do ciclo

  • Execute o mypy pelo mesmo ambiente Python do projeto e alinhe --python-version ao alvo escolhido.
  • Leia arquivo, linha, tipo esperado e tipo recebido para chegar à causa de atribuições, argumentos e retornos incompatíveis.
  • Use reveal_type como consulta temporária quando precisar confirmar a inferência; retire-o antes da execução normal.
  • Prefira contratos concretos às fugas com Any; uma operação específica pede um tipo que a garanta.
  • Use --strict como revisão adicional, sem confundi-lo com cobertura total ou validação em tempo de execução.

Tutorial concluído

Parabéns! Você concluiu: Verificar anotações com mypy

Você concluiu o ciclo de verificação com mypy: analisou diagnósticos, corrigiu contratos e valores, revisou o efeito de Any e confirmou o módulo em modo estrito. Na próxima etapa, você vai aplicar esses contratos a coleções e estruturas aninhadas.

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso