
Passo 1 de 7
Ler e escrever uma assinatura com Callable
Represente a forma de chamada de uma função como um tipo e separe o chamável do valor que ele produz.
Trilha de aprendizado · Nível 12 · Tutorial 4
Descrever assinaturas de funções usadas como valores e verificar se funções, closures ou objetos chamáveis atendem ao contrato esperado.
Ler e escrever uma assinatura com Callable
Represente a forma de chamada de uma função como um tipo e separe o chamável do valor que ele produz. 2 min
Anotar uma função que recebe um callback
Defina o contrato de um callback observando como a função consumidora o chama e usa seu resultado. 2 min
Decidir se um callback pode substituir outro
Compare callbacks pelo que o consumidor pode chamar e pelo resultado que ele precisa receber. 3 min
Usar instâncias chamáveis no mesmo contrato
Use a assinatura de __call__ para verificar quando uma instância pode ocupar o lugar de um callback Callable. 2 min
Anotar a função produzida por uma fábrica
Diferencie o retorno da fábrica do retorno da função interna e verifique o contrato produzido com mypy. 3 min
Reconhecer o que Callable não verifica
Compare assinaturas explícitas e flexíveis para entender quais garantias o verificador preserva — e quais ele deixa de oferecer. 2 min
Aplicar e revisar os contratos de chamada
Integre um consumidor, uma fábrica de closures e uma instância chamável em um fluxo de transformações de texto, verificando o contrato com mypy. 4 min

Passo 1 de 7
Represente a forma de chamada de uma função como um tipo e separe o chamável do valor que ele produz.
Em Python 3.12 ou superior, importe Callable de collections.abc.
A forma geral é:
Callable[[tipos dos argumentos], tipo do retorno]
A lista interna descreve os argumentos por posição. O último tipo descreve o valor devolvido quando o objeto é chamado.
A anotação separa o que entra na chamada do que sai dela.

Callable[[str], int]: recebe um str e, ao ser chamado, produz um int.
A variável medir guarda a função. Já tamanho guarda o resultado da chamada.
from collections.abc import Callable
def contar_caracteres(texto: str) -> int:
return len(texto)
medir: Callable[[str], int] = contar_caracteres
tamanho: int = medir("Python")
print(tamanho) # 6Dica
Em Callable[[str], int], str é o tipo do argumento fornecido na chamada; int é o tipo do valor produzido. Portanto, medir não é um int: ele é um objeto chamável que produz int.
Uma lista vazia indica uma chamada sem argumentos. None no retorno indica que a chamada não produz um valor útil.
from collections.abc import Callable
def versao() -> str:
return "3.12"
def avisar() -> None:
print("Processo concluído")
obter_versao: Callable[[], str] = versao
emitir_aviso: Callable[[], None] = avisar
texto: str = obter_versao()
resultado: None = emitir_aviso()Exemplo
Callable[[], str] significa: “algo que pode ser chamado sem argumentos e devolve str”.
Callable[[], None] significa: “algo que pode ser chamado sem argumentos e não devolve um valor útil”.
Considere a assinatura:
def registrar() -> None:
print("evento registrado")Complete a anotação:
acao: Callable[____, ____] = registrar
Passo 2 de 7
Defina o contrato de um callback observando como a função consumidora o chama e usa seu resultado.
Ao anotar um parâmetro que recebe uma função, observe o que o consumidor faz com ela. Se ele fornece uma str ao callback e depois espera uma str de volta, o contrato é Callable[[str], str].
A primeira lista descreve os argumentos recebidos pelo callback; o último tipo descreve o valor que ele devolve.
O consumidor envia um texto ao callback e usa o texto transformado que recebe de volta.

aplicar_transformacao chama o callback com uma str e recebe uma str.
A anotação descreve a chamada que este corpo de função tem permissão de fazer.
from collections.abc import Callable
def aplicar_transformacao(
texto: str,
transformar: Callable[[str], str],
) -> str:
resultado = transformar(texto)
return f"Resultado: {resultado}"
def deixar_maiusculo(valor: str) -> str:
return valor.upper()
print(aplicar_transformacao("olá", deixar_maiusculo))
# Resultado: OLÁCom essa anotação, o mypy verifica duas coisas relacionadas:
transformar(texto), o consumidor só pode passar uma str e deve tratar o resultado como str.aplicar_transformacao, a função fornecida precisa atender a essa assinatura.Isso é verificação estática: a anotação não testa nem adapta valores enquanto o programa está rodando.
Execute python -m mypy arquivo.py para obter diagnósticos como estes.
from collections.abc import Callable
def aplicar_transformacao(
texto: str,
transformar: Callable[[str], str],
) -> str:
return transformar(texto)
def contar_caracteres(valor: str) -> int:
return len(valor)
aplicar_transformacao("casa", contar_caracteres)
# mypy: argumento incompatível: a função retorna int,
# mas o callback prometido deve retornar str
# O próprio consumidor também é verificado:
# transformar(10)
# mypy: argumento incompatível; era esperada uma strComplete a anotação de normalizar:
from collections.abc import Callable
def saudar(nome: str, normalizar: ___) -> str:
limpo = normalizar(nome)
return f"Olá, {limpo}!"Na função saudar do exercício anterior, explique por que o contrato de normalizar é Callable[[str], str].
Escreva pelo menos 40 caracteres (0/40).

Passo 3 de 7
Compare callbacks pelo que o consumidor pode chamar e pelo resultado que ele precisa receber.
Se um parâmetro é Callable[[Animal], Animal], o consumidor tem o direito de fornecer qualquer Animal e de usar o resultado como Animal.
Para substituir esse callback com segurança, o valor fornecido precisa:
Animal.As assinaturas não precisam ser idênticas. O critério é atender às chamadas previstas pelo contrato.

Um parâmetro mais abrangente pode aceitar o Animal enviado; um retorno mais específico ainda pode ser usado como Animal.
Exemplo
Contrato esperado: Callable[[Animal], Animal]
Uma função def identificar(valor: object) -> Dog pode ser compatível: ela aceita até mais do que Animal, e um Dog pode ser usado onde se espera Animal.
Já def passear(cao: Dog) -> Animal não é compatível: o consumidor poderia enviar outro Animal, como um Gato.
Execute este arquivo com: python -m mypy callbacks.py
from collections.abc import Callable
class Animal:
pass
class Dog(Animal):
pass
class Cat(Animal):
pass
def aplicar(animal: Animal, acao: Callable[[Animal], Animal]) -> Animal:
return acao(animal)
# Aceita uma entrada mais ampla e produz uma saída mais específica.
def identificar(valor: object) -> Dog:
return Dog()
# Exige uma entrada específica demais.
def treinar(cao: Dog) -> Animal:
return cao
# Produz uma saída ampla demais.
def embrulhar(animal: Animal) -> object:
return animal
resultado = aplicar(Cat(), identificar) # Aceito
# aplicar(Cat(), treinar) # Erro: Cat pode ser enviada, mas treinar exige Dog
# aplicar(Cat(), embrulhar) # Erro: object não é garantidamente um Animal
Dica
O mypy rejeita treinar não porque o nome ou a quantidade de parâmetros difere, mas porque aplicar pode chamar o callback com um Cat. Também rejeita embrulhar porque quem recebe o resultado espera as operações garantidas por Animal, não apenas por object.
Associe cada assinatura fornecida ao seu resultado ao ser passada para um parâmetro Callable[[Animal], Animal].
Toque em um item e depois no par correspondente.

Passo 4 de 7
Use a assinatura de call para verificar quando uma instância pode ocupar o lugar de um callback Callable.
Se um consumidor espera um Callable[[str], str], ele não exige necessariamente uma função definida com def. Uma instância também atende ao contrato quando pode ser chamada com uma str e produz uma str.
Isso permite usar um objeto chamável quando a transformação precisa guardar uma configuração, como um prefixo.

Para o consumidor, importa a assinatura da chamada: str entra e str sai.
Em __call__, self pertence ao mecanismo do método. Quem chama a instância fornece apenas texto; por isso self não entra na lista do Callable.
from collections.abc import Callable
def aplicar(texto: str, transformacao: Callable[[str], str]) -> str:
return transformacao(texto)
def remover_espacos(texto: str) -> str:
return texto.strip()
class ComPrefixo:
def __init__(self, prefixo: str) -> None:
self.prefixo = prefixo
def __call__(self, texto: str) -> str:
return f"{self.prefixo}{texto}"
print(aplicar(" oi ", remover_espacos)) # oi
saudacao = ComPrefixo("Olá, ")
print(aplicar("Ana", saudacao)) # Olá, AnaDica
A chamada saudacao("Ana") usa a assinatura visível (__call__(texto: str) -> str). Assim, ela corresponde a Callable[[str], str], e não a Callable[[ComPrefixo, str], str].
A instância abaixo pode ser passada para um parâmetro anotado como Callable[[str], str].
class AjustarCaixa:
def __call__(self, texto: str) -> str:
return texto.upper()Um consumidor exige Callable[[str], str].
class ComPrefixo:
def __call__(self, texto: str) -> str:
return f"> {texto}"
class Repetir:
def __call__(self, texto: str, vezes: int) -> str:
return texto * vezesQual instância pode ser fornecida ao consumidor? Justifique pela assinatura de __call__ e explique por que self não aparece em Callable[[str], str].
Escreva pelo menos 50 caracteres (0/50).

Passo 5 de 7
Diferencie o retorno da fábrica do retorno da função interna e verifique o contrato produzido com mypy.
Uma fábrica recebe valores de configuração e devolve um objeto chamável. Portanto, a anotação depois de -> descreve a função produzida, não o texto que ela produzirá mais tarde.
Em criar_formatador, prefixo pertence à chamada da fábrica. Já texto pertence à chamada do formatador devolvido.
Observe que há duas chamadas separadas.

Primeira chamada: configurar a fábrica. Segunda chamada: usar a função produzida.
A lista interna de Callable contém os tipos dos argumentos da função devolvida. O último tipo é o retorno dessa função.
from collections.abc import Callable
def criar_formatador(prefixo: str) -> Callable[[str], str]:
def formatar(texto: str) -> str:
return f"{prefixo}: {texto}"
return formatar
formatar_aviso = criar_formatador("AVISO")
print(formatar_aviso("Porta aberta")) # AVISO: Porta abertaA fábrica prometeu Callable[[str], str]. Assim, return formatar devolve a própria função interna, que ainda espera receber um str.
Já formatar("pronto") executa a função interna imediatamente e produz um str. Esse valor não atende ao contrato de retorno da fábrica.
A segunda versão quebra a promessa feita após ->. O mypy aponta que um str não pode ser retornado onde se espera um Callable[[str], str].
from collections.abc import Callable
def fabrica_correta(prefixo: str) -> Callable[[str], str]:
def formatar(texto: str) -> str:
return f"{prefixo}: {texto}"
return formatar # devolve a função
def fabrica_incorreta(prefixo: str) -> Callable[[str], str]:
def formatar(texto: str) -> str:
return f"{prefixo}: {texto}"
return formatar("pronto") # devolve um str: incompatívelComplete a anotação: def criar_formatador(prefixo: str) -> ______:
Crie um arquivo fabrica.py com o código abaixo e execute python -m mypy fabrica.py --python-version 3.12. A consulta reveal_type é temporária: remova-a antes de executar o arquivo normalmente com Python.
A última chamada foi incluída de propósito para o mypy verificar o argumento da função produzida.
from collections.abc import Callable
def criar_formatador(prefixo: str) -> Callable[[str], str]:
def formatar(texto: str) -> str:
return f"{prefixo}: {texto}"
return formatar
formatar_titulo = criar_formatador("TÍTULO")
reveal_type(formatar_titulo)
formatar_titulo(10) # chamada incompatível de propósitoApós rodar o mypy, relate: qual assinatura foi revelada para formatar_titulo e por que formatar_titulo(10) recebeu um diagnóstico? Inclua que providência deve ser tomada com reveal_type antes da execução normal.
Escreva pelo menos 40 caracteres (0/40).

Passo 6 de 7
Compare assinaturas explícitas e flexíveis para entender quais garantias o verificador preserva — e quais ele deixa de oferecer.
Uma assinatura explícita informa entradas e saída:
Callable[[str, int], str]
Já Callable[..., str] só preserva a promessa de que a chamada produz str. As reticências dizem ao mypy que, por esse contrato, os argumentos não serão especificados nem verificados.
Compare as informações mantidas em cada anotação.

A saída continua no contrato; as entradas deixam de fazer parte dele com ....
Execute o mypy neste arquivo e compare os dois usos.
from collections.abc import Callable
def rotular(texto: str, vezes: int) -> str:
return f"{texto} " * vezes
precisa: Callable[[str, int], str] = rotular
aberta: Callable[..., str] = rotular
precisa("oi", "duas") # mypy: argumento incompatível
aberta("oi", "duas") # passa pela anotação; falha ao executar
resultado: str = aberta("olá", 2)
Atenção
Callable[..., str] não altera rotular. Ela ainda exige um str e um int em tempo de execução. A anotação aberta apenas perde a capacidade de acusar essa chamada incompatível pelo contrato de aberta.
Em ambos os casos, o resultado ainda é tratado como str.
Callable[[str, int], str] descreve tipos de argumentos posicionais. Ele não registra que uma implementação espera nomes específicos em chamadas nomeadas, nem expressa exigências como parâmetros exclusivamente nomeados.
Além disso, Callable só promete que o valor pode ser chamado. Ele não pode exigir, por exemplo, um atributo .nome ou um método .reiniciar(). Quando o consumidor precisa dessas outras operações, será necessário um contrato mais expressivo, visto adiante.
Exemplo
Considere uma função que só aceita a configuração por nome:
def formatar(texto: str, *, maiusculas: bool) -> str:
return texto.upper() if maiusculas else textoUma lista em Callable pode indicar que há valores str, bool e retorno str, mas não preserva que maiusculas deve ser fornecido exclusivamente como argumento nomeado.
No código da tela anterior, qual é a principal diferença estática entre precisa e aberta?

Passo 7 de 7
Integre um consumidor, uma fábrica de closures e uma instância chamável em um fluxo de transformações de texto, verificando o contrato com mypy.
Neste fluxo, a função aplicar pode chamar qualquer transformação com um str e precisa receber outro str como resultado. Portanto, o contrato comum é Callable[[str], str].
A origem do valor chamável pode variar: uma função criada por uma fábrica ou uma instância que implementa __call__. O que importa para o consumidor é a assinatura de chamada compatível.
Observe onde cada assinatura atua.

A fábrica retorna uma transformação; a instância também pode ser a transformação. Ambas precisam aceitar str e retornar str.
No seu computador, crie um arquivo chamado fluxo.py com o código abaixo. Complete as duas anotações marcadas por ??? usando Callable.
Depois, descomente a última linha e execute python -m mypy --strict fluxo.py. Corrija a incompatibilidade na origem: a transformação fornecida a aplicar deve produzir texto. Não use Any, cast nem Callable[..., str] como atalho.
from collections.abc import Callable
def aplicar(texto: str, transformacao: ???) -> str:
return transformacao(texto)
def criar_prefixo(prefixo: str) -> ???:
def transformar(texto: str) -> str:
return f"{prefixo}{texto}"
return transformar
class Normalizador:
def __init__(self, largura: int) -> None:
self.largura = largura
def __call__(self, texto: str) -> str:
return " ".join(texto.split()).ljust(self.largura)
def medir(texto: str) -> int:
return len(texto)
com_prefixo = criar_prefixo("Aviso: ")
print(aplicar(" pronto ", Normalizador(12)))
print(aplicar("concluído", com_prefixo))
# Descomente para observar o diagnóstico e corrija a origem:
# print(aplicar("concluído", medir))Dica
O erro não está em aplicar: ela tem o direito de usar o resultado como str. Se medir for usada como transformação nesse fluxo, adapte ou substitua essa função para que seu retorno seja str. Se a intenção for conservar uma medida numérica, ela pertence a outro contrato de chamada.
Após ajustar o arquivo e rodar mypy, responda:
aplicar e no retorno de criar_prefixo?medir?Normalizador(12) é aceito?Callable[..., str] não é uma correção apropriada aqui?Escreva pelo menos 180 caracteres (0/180).
Resumo
Use a assinatura exigida pelo ponto que consome o chamável como referência.
Callable[[str], str] promete uma chamada que recebe um texto e produz um texto.Callable; o retorno da fábrica é a função, não o resultado da função.__call__(self, texto: str) -> str atende ao mesmo contrato sem herdar de Callable.Callable[..., retorno].Parabéns! Você concluiu: Anotar funções recebidas e retornadas com Callable
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks