Capítulo 37, Intermediário
Type hints
Anotações de tipo documentam o contrato do código e permitem que ferramentas achem erros antes de rodar. O Python em si ignora as anotações.
Código deste capítulo: intermediario/cap37_type_hints.py
Anotar parâmetros e retorno
A anotação vai depois de dois pontos nos parâmetros e depois de -> no retorno. Elas ficam guardadas em __annotations__, mas o interpretador não as verifica:
def saudar(nome: str, vezes: int = 1) -> str:
return (f"Olá, {nome}! " * vezes).strip()
print(saudar("Ana", 2))
print(saudar.__annotations__)
print(saudar(123))
Olá, Ana! Olá, Ana!
{'nome': <class 'str'>, 'vezes': <class 'int'>, 'return': <class 'str'>}
Olá, 123!
A última chamada passa um inteiro onde se esperava texto, e o Python roda sem reclamar. Quem acusa o erro é uma ferramenta externa, o verificador de tipos.
Coleções, opcionais e uniões
Desde o Python 3.9 você pode usar list[int] e dict[str, int] diretamente. A barra vertical (int | None, desde o 3.10) expressa uma união:
def media(valores: list[float]) -> float:
return sum(valores) / len(valores)
def buscar(config: dict[str, int], chave: str) -> int | None:
return config.get(chave)
print(media([1.0, 2.0, 3.0]), buscar({"porta": 80}, "host"))
2.0 None
Aliases, funções e estruturas
Para nomear um tipo complexo, o Python 3.12 trouxe a instrução type. Funções como argumento usam Callable. E para registros com forma conhecida há NamedTuple e TypedDict:
from collections.abc import Callable
from typing import NamedTuple, TypedDict
type Predicado = Callable[[int], bool]
def filtrar(numeros: list[int], teste: Predicado) -> list[int]:
return [n for n in numeros if teste(n)]
class Ponto(NamedTuple):
x: int
y: int
class Usuario(TypedDict):
nome: str
idade: int
u: Usuario = {"nome": "Ana", "idade": 30}
print(filtrar([1, 2, 3, 4], lambda n: n % 2 == 0))
print(Ponto(1, 2), u)
[2, 4]
Ponto(x=1, y=2) {'nome': 'Ana', 'idade': 30}
A constante "de verdade" para ferramentas de tipo é typing.Final: LIMITE: Final = 3 avisa que reatribuir é um erro.
Quem verifica
O verificador mais usado é o mypy. O pyright é outra boa opção. Os dois leem o código sem executá-lo e apontam inconsistências. Instale como ferramenta de desenvolvimento do projeto:
uv add --dev mypy
uv run mypy exemplos/tipos/erro_de_tipo.py
O arquivo a verificar chama uma função com o tipo errado:
def dobrar(valor: int) -> int:
return valor * 2
dobrar("3")
exemplos/tipos/erro_de_tipo.py:5: error: Argument 1 to "dobrar" has incompatible type "str"; expected "int" [arg-type]
Found 1 error in 1 file (checked 1 source file)
Referências a tipos ainda não definidos
Antes do Python 3.14, anotar com uma classe definida mais abaixo exigia aspas (
"Cliente") oufrom __future__ import annotations. A partir do 3.14, as anotações são avaliadas de forma adiada por padrão, e esse problema desaparece. Se o seu projeto ainda suporta versões anteriores, mantenha o__future__.
Exercício 1
Anote uma função de agrupamento
Escreva agrupar_por_inicial(palavras: list[str]) -> dict[str, list[str]], que agrupe as palavras pela primeira letra em minúscula.