Módulo 2 - Tipagem estática

Callable, Any e apelidos de tipo

9 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

O que você vai aprender

  • Anotar funções que recebem ou devolvem funções com Callable.
  • Entender que Any desliga a verificação e usá-lo com parcimônia.
  • Criar apelidos de tipo para dar nome a tipos complexos.
  • Escolher entre Any, object e um tipo específico com critério.

Callable: quando a função é o argumento

Funções são objetos em Python, então uma função pode receber outra função como argumento. Para anotar isso existe o Callable, importado do typing. A sintaxe tem duas partes: uma lista com os tipos dos parâmetros e, depois, o tipo de retorno. Callable[[int, int], int] descreve uma função que recebe dois inteiros e devolve um inteiro. Isso é comum em código que recebe uma função de comparação, um callback ou uma operação para aplicar.

from typing import Callable

def aplicar(operacao: Callable[[int, int], int], a: int, b: int) -> int:
    return operacao(a, b)

def somar(x: int, y: int) -> int:
    return x + y

def multiplicar(x: int, y: int) -> int:
    return x * y

print(aplicar(somar, 3, 4))       # 7
print(aplicar(multiplicar, 3, 4))  # 12

aplicar recebe uma função Callable[[int, int], int] e a usa com dois inteiros.

No exemplo, aplicar aceita qualquer função que se encaixe no contrato: dois inteiros entram, um inteiro sai. Tanto somar quanto multiplicar servem. Se você tentasse passar uma função com assinatura diferente, o mypy avisaria. Quando os parâmetros não importam para a anotação, você pode usar reticências no lugar da lista: Callable[..., int] aceita qualquer assinatura desde que o retorno seja inteiro.

Any: o tipo que desliga a verificação

Any é um tipo especial que combina com tudo. Um valor anotado como Any pode receber qualquer coisa e ser usado de qualquer jeito, sem o mypy reclamar. Isso soa conveniente, mas é justamente o problema: onde entra Any, a verificação de tipos se desliga. Um pouco de Any é inevitável, por exemplo ao lidar com dados de fora ainda sem forma definida. Muito Any transforma o código tipado em código sem tipos, com todo o custo de escrever anotações e nenhum benefício.

Any

  • Aceita qualquer valor e permite qualquer operação
  • Desliga a verificação naquele ponto
  • Use quando o tipo é genuinamente desconhecido
  • Perigoso se virar hábito: mascara erros

object

  • Aceita qualquer valor, pois tudo herda de object
  • Mantém a verificação: só permite o que object oferece
  • Use quando aceita qualquer coisa mas quer segurança
  • Mais seguro: o mypy cobra checagem antes de usar

Apelidos de tipo para legibilidade

Quando um tipo fica longo, repeti-lo em várias assinaturas polui o código. Um apelido de tipo resolve isso: você atribui o tipo a um nome e usa o nome no lugar. Se um sistema de coordenadas usa muito list[tuple[float, float]], criar Trajeto = list[tuple[float, float]] deixa as assinaturas curtas e o significado claro. O apelido não cria um tipo novo; é só um nome mais legível para o mesmo tipo. Em versões recentes há a palavra type para deixar isso ainda mais explícito.

Trajeto = list[tuple[float, float]]
TabelaPrecos = dict[str, float]

def distancia_total(rota: Trajeto) -> float:
    total = 0.0
    for i in range(1, len(rota)):
        x1, y1 = rota[i - 1]
        x2, y2 = rota[i]
        total += ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
    return total

caminho: Trajeto = [(0.0, 0.0), (3.0, 4.0)]
print(distancia_total(caminho))  # 5.0

Trajeto é um apelido para list[tuple[float, float]]; a assinatura fica legível.

O apelido Trajeto conta a intenção que list[tuple[float, float]] esconde. Quem lê distancia_total(rota: Trajeto) entende de imediato que a função recebe um caminho, não uma lista qualquer de pares. Esse tipo de nomeação é engenharia de legibilidade: o programa faz o mesmo, mas fica mais fácil de manter. Na próxima aula você conhece TypeVar e generics, que levam essa ideia adiante ao escrever código que funciona para qualquer tipo sem abrir mão da verificação.

Teste rápido

Por que usar Any por toda parte anula a vantagem da tipagem?

Perguntas frequentes

Como anoto uma função que não recebe nenhum argumento?
Com uma lista de parâmetros vazia: Callable[[], int] descreve uma função sem argumentos que devolve um inteiro. Os colchetes internos ficam vazios justamente para indicar que nada entra. O segundo elemento continua sendo o tipo de retorno.
Quando é aceitável usar Any de verdade?
Quando o tipo é genuinamente desconhecido naquele ponto, como ao receber dados de uma fonte externa sem forma fixa, ou ao integrar com uma biblioteca sem tipos. Mesmo assim, o ideal é converter esse Any para um tipo concreto o quanto antes, validando o dado na fronteira.
Apelido de tipo cria um tipo novo?
Não. Um apelido é só um nome alternativo para um tipo existente. Trajeto = list[tuple[float, float]] não gera uma classe nova; para o mypy, Trajeto e list[tuple[float, float]] são idênticos. O ganho é de legibilidade, não de comportamento.
Callable serve para métodos também, não só funções soltas?
Sim. Métodos, funções e qualquer objeto que se possa chamar com parênteses se encaixam no tipo Callable, desde que a assinatura combine. Isso inclui funções lambda e instâncias de classes que definem o método especial de chamada. O que importa é a forma de chamar.
Qual a diferença prática entre Any e object no dia a dia?
Com Any você pode fazer qualquer operação sem o mypy reclamar, o que é arriscado. Com object o mypy só permite o que todo objeto tem e cobra que você verifique o tipo real antes de usar métodos específicos. Para aceitar qualquer valor com segurança, object é a escolha melhor.
Preciso importar Callable e Any de onde?
Ambos vêm do módulo typing: from typing import Callable, Any. Em versões recentes, Callable também está disponível em collections.abc, mas importar do typing continua funcionando e é o mais comum em material didático.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.