
Passo 1 de 7
Distinguir a criação da instância de sua chamada
Veja como os parênteses têm efeitos diferentes ao chamar uma classe e ao chamar uma instância que implementa call.
Trilha de aprendizado · Nível 11 · Tutorial 5
Ao concluir, você poderá criar instâncias que funcionam como operações chamáveis e usar seu estado para configurar ou acompanhar chamadas.
Distinguir a criação da instância de sua chamada
Veja como os parênteses têm efeitos diferentes ao chamar uma classe e ao chamar uma instância que implementa __call__. 1 min
Definir os argumentos e o retorno da operação
Separe a configuração guardada no objeto dos valores recebidos em cada chamada. 2 min
Acompanhar chamadas com estado por instância
Amplie o Multiplicador para registrar chamadas sem misturar o estado de objetos diferentes. 2 min
Passar o objeto para uma função de alta ordem
Use uma instância de Multiplicador diretamente em map e observe quando suas chamadas realmente acontecem. 2 min
Entender o que callable verifica
Use callable para consultar se um objeto pode ser chamado, sem confundir essa consulta com uma execução bem-sucedida. 1 min
Escolher entre função, closure e objeto chamável
Escolha a abstração mais simples de acordo com a necessidade de configuração, estado e interface pública. 1 min
Aplicar e verificar um objeto chamável completo
Implemente e execute um exemplo completo para conferir retornos, contadores independentes, reinicialização e uso com map. 3 min

Passo 1 de 7
Veja como os parênteses têm efeitos diferentes ao chamar uma classe e ao chamar uma instância que implementa call.
Uma classe pode definir __call__ para dar às suas instâncias o comportamento de uma operação chamável.
No exemplo, Multiplicador(3) chama a classe e cria um objeto configurado com fator 3. Depois, triplo(10) chama a instância já criada: o Python executa triplo.__call__(10).
Observe que o primeiro resultado é um objeto; o segundo é o valor transformado por esse objeto.

Chamar a classe constrói a instância. Chamar a instância aciona sua operação.
Execute este código no seu Python para observar os dois resultados.
class Multiplicador:
def __init__(self, fator):
self.fator = fator
def __call__(self, valor):
return self.fator * valor
triplo = Multiplicador(3)
print(triplo)
print(triplo(10))Exemplo
triplo = Multiplicador(3) executa __init__ e atribui uma instância à variável triplo.
triplo(10) executa __call__ nessa instância e devolve 30. Como a classe não definiu __str__ ou __repr__, a primeira impressão mostra a representação padrão do objeto, com um endereço que varia em cada execução.
Associe cada expressão ao efeito principal.
Toque em um item e depois no par correspondente.

Passo 2 de 7
Separe a configuração guardada no objeto dos valores recebidos em cada chamada.
No Multiplicador, o fator é uma configuração persistente: ele é recebido uma vez em __init__ e fica em self.fator.
Já valor e ajuste pertencem a cada execução de __call__. Ao escrever dobro(5), você não passa self: Python associa automaticamente a instância a esse primeiro parâmetro.
A instância conserva o fator; cada chamada fornece seu próprio valor e, opcionalmente, um ajuste.

fator vem da configuração do objeto; valor e ajuste vêm da chamada.
O ajuste padrão é aplicado depois da multiplicação.
class Multiplicador:
def __init__(self, fator):
self.fator = fator
def __call__(self, valor, ajuste=0):
return self.fator * valor + ajuste
dobro = Multiplicador(2)
print(dobro(5)) # 10
print(dobro(5, 1)) # 11
print(dobro(5, ajuste=3)) # 13Dica
__init__ inicializa a instância e deve retornar None. Já __call__ é uma operação comum: pode usar return para fazer com que a expressão dobro(...) produza um resultado.
Considere triplo = Multiplicador(3) e depois triplo(4, ajuste=2). Quais valores são argumentos da execução de __call__?
Complete o corpo de __call__ para que Multiplicador(4)(3, ajuste=2) devolva 14:
return self.fator * valor ___ ajuste

Passo 3 de 7
Amplie o Multiplicador para registrar chamadas sem misturar o estado de objetos diferentes.
Além do fator configurado na criação, cada Multiplicador pode guardar quantas chamadas foram concluídas. O atributo chamadas começa em 0 em __init__, portanto pertence a cada instância.
Em __call__, primeiro calcule o resultado. Em seguida, incremente o contador e devolva o resultado. Assim, uma chamada contabilizada é aquela cujo cálculo chegou ao fim com sucesso.
Observe o que permanece, o que é devolvido e o que muda.

O fator é configuração conservada; o produto é o retorno; chamadas é o estado atualizado.
class Multiplicador:
def __init__(self, fator):
self.fator = fator
self.chamadas = 0
def __call__(self, valor, ajuste=0):
resultado = self.fator * valor + ajuste
self.chamadas += 1
return resultado
def reiniciar(self):
self.chamadas = 0Exemplo
por_dois = Multiplicador(2)
por_dez = Multiplicador(10)
print(por_dois(3)) # 6
print(por_dez(3)) # 30
print(por_dois(4)) # 8
print(por_dois.chamadas) # 2
print(por_dez.chamadas) # 1As instâncias usam a mesma definição de classe, mas cada uma conserva seu próprio fator e seu próprio chamadas.
As chamadas foram intercaladas, mas cada faixa registra apenas o objeto correspondente.

Uma chamada em por_dez não altera o contador de por_dois, e vice-versa.
reiniciar() altera somente self.chamadas: o contador da instância que recebeu a chamada. Ele não muda o fator e não alcança outras instâncias.
por_dois.reiniciar()
print(por_dois.chamadas) # 0
print(por_dez.chamadas) # 1
print(por_dois.fator) # 2Dica
Incrementar depois do cálculo deixa explícito que o contador representa cálculos concluídos. Se o cálculo falhar antes dessa linha, a chamada não será contabilizada.
Partindo de a = Multiplicador(2) e b = Multiplicador(5), ambos com contador 0, coloque os estados na ordem em que ocorrem após esta sequência: a(3), b(4), a.reiniciar().

Passo 4 de 7
Use uma instância de Multiplicador diretamente em map e observe quando suas chamadas realmente acontecem.
map recebe primeiro uma operação chamável e depois uma fonte de valores. Como multiplicar é uma instância que implementa __call__, passe o próprio objeto: map(multiplicar, valores).
Não escreva multiplicar(): esses parênteses tentariam executar a operação antes de map fornecer um valor.
Cada item da fonte é entregue à mesma instância. Com uma única fonte, map fornece um argumento por chamada.

map chama a mesma instância uma vez para cada valor consumido.
A assinatura aceita um valor por chamada; ajuste permanece com seu valor padrão de 0.
class Multiplicador:
def __init__(self, fator):
self.fator = fator
self.chamadas = 0
def __call__(self, valor, ajuste=0):
resultado = valor * self.fator + ajuste
self.chamadas += 1
return resultado
multiplicar_por_3 = Multiplicador(3)
valores = [2, 4, 6]
transformados = list(map(multiplicar_por_3, valores))
print(transformados) # [6, 12, 18]
print(multiplicar_por_3.chamadas) # 3Dica
map(...) produz um iterador. Ao fazer list(...), você o consome integralmente agora: os resultados são criados e as três chamadas são contabilizadas. Antes desse consumo, não espere que todas as transformações já tenham ocorrido.
Complete o primeiro argumento para transformar [1, 5] com a instância multiplicar_por_3:
resultado = list(map(_____, [1, 5]))

Passo 5 de 7
Use callable para consultar se um objeto pode ser chamado, sem confundir essa consulta com uma execução bem-sucedida.
callable(objeto) consulta se o objeto pode ser usado com parênteses. O resultado é True ou False, e essa consulta não executa a operação.
Por isso, verificar callable(mult2) não multiplica valor nenhum nem altera o contador de chamadas da instância.
A consulta verifica a possibilidade geral de chamada; os argumentos e o resultado só entram em cena quando você realmente chama o objeto.

callable pergunta “pode ser chamado?” — não pergunta “esta chamada específica vai funcionar?”.
Execute este exemplo no Python:
class Multiplicador:
def __init__(self, fator):
self.fator = fator
def __call__(self, valor):
return self.fator * valor
def dobrar(numero):
return numero * 2
mult3 = Multiplicador(3)
print(callable(dobrar)) # True: função
print(callable(Multiplicador)) # True: classe cria instâncias
print(callable(mult3)) # True: instância tem __call__
print(callable(42)) # False
Atenção
Uma classe usual é chamável porque Classe(...) tenta criar uma instância. Já uma instância só será chamável se sua classe definir __call__. Portanto, callable(Multiplicador) e callable(mult3) são consultas independentes.
Mesmo com callable(mult3) igual a True, estas chamadas têm resultados diferentes:
print(callable(mult3)) # True
print(mult3(5)) # 15
# mult3() # TypeError: falta o argumento valor
# mult3(5, 2) # TypeError: há um argumento posicional extra
def inverter(numero):
return 1 / numero
print(callable(inverter)) # True
# print(inverter(0)) # ZeroDivisionError durante a execução
Dica
callable(objeto): o objeto pode ser chamado?objeto(argumentos): os argumentos combinam com a assinatura?Um True responde apenas à primeira pergunta.
Se mult3 é uma instância de Multiplicador com __call__, executar callable(mult3) incrementa seu contador de chamadas.
Se callable(inverter) retorna True, então inverter(0) necessariamente retorna um número.

Passo 6 de 7
Escolha a abstração mais simples de acordo com a necessidade de configuração, estado e interface pública.
Comece pela alternativa mais simples que expressa o problema:
Ter estado não obriga o uso de uma classe. A pergunta é: esse estado precisa fazer parte de uma interface que outras pessoas possam consultar ou controlar?
Compare as necessidades antes de escolher.

Função para operação direta; closure para estado ou configuração restritos à chamada; objeto chamável quando o estado e ações relacionadas compõem uma interface.
Exemplo
1. Dobrar um número uma vez
def dobrar(valor):
return valor * 2Uma função é suficiente: não há configuração variável nem estado para acompanhar.
2. Criar uma operação configurada pelo fator
Uma closure pode ser adequada quando a única interface necessária é chamar a operação resultante, como por_tres(5).
3. Multiplicar e acompanhar o uso
Um Multiplicador chamável faz sentido se o programa precisa consultar chamadas e executar reiniciar(). Nesse caso, fator, contador e reinicialização pertencem à mesma interface.
O contador sozinho não decide a escolha: se ele ficar inteiramente interno e ninguém precisar consultá-lo ou reiniciá-lo, uma closure ainda pode ser uma boa solução.
Dica
Escolha pelo que o código consumidor precisa usar, não pelo desejo de “usar classes”. Se ele só chama uma operação, função ou closure tende a ser mais direta. Se ele também consulta e controla o estado relacionado, o objeto chamável pode deixar essa relação explícita.
Um programa cria operações de desconto com percentuais diferentes. Cada operação será chamada muitas vezes para calcular preços, mas o programa não precisa consultar quantas chamadas ocorreram nem reiniciar qualquer estado.
Você escolheria uma função, uma closure ou um objeto chamável? Justifique usando as necessidades da interface.
Escreva pelo menos 80 caracteres (0/80).

Passo 7 de 7
Implemente e execute um exemplo completo para conferir retornos, contadores independentes, reinicialização e uso com map.
No seu editor, crie um arquivo կոչado multiplicador.py, copie o código abaixo e execute com Python 3. Os asserts não exibem nada quando passam; ao final, os prints mostram o estado confirmado.
Observe que fator é a configuração persistente, chamadas é o estado de cada instância e valor/ajuste pertencem a cada execução.
class Multiplicador:
def __init__(self, fator):
self.fator = fator
self.chamadas = 0
def __call__(self, valor, ajuste=0):
resultado = valor * self.fator + ajuste
self.chamadas += 1
return resultado
def reiniciar(self):
self.chamadas = 0
dobro = Multiplicador(2)
triplo = Multiplicador(3)
# Valor padrão de ajuste e argumento nomeado.
assert dobro(5) == 10
assert dobro(valor=4, ajuste=1) == 9
assert dobro.chamadas == 2
# A outra instância tem configuração e contador próprios.
assert triplo(5) == 15
assert triplo.chamadas == 1
# Reiniciar afeta somente o objeto que recebeu a chamada.
dobro.reiniciar()
assert dobro.chamadas == 0
assert triplo.chamadas == 1
# map recebe a instância, sem parênteses: ele a chamará para cada valor.
resultados = list(map(dobro, [1, 2, 3]))
assert resultados == [2, 4, 6]
assert dobro.chamadas == 3
assert triplo.chamadas == 1
print(resultados) # [2, 4, 6]
print(dobro.chamadas) # 3
print(triplo.chamadas) # 1A sequência de chamadas deixa claro que o retorno de __call__ e o contador são coisas diferentes: o retorno é entregue imediatamente; o contador permanece no objeto que foi chamado.

Depois do roteiro: dobro produziu [2, 4, 6] em map e terminou com 3 chamadas; triplo continuou com 1 chamada.
Dica
Em map(dobro, [1, 2, 3]), você passa o objeto chamável. O map fornece um valor por vez e executa algo equivalente a dobro(1), dobro(2) e dobro(3). Já map(dobro(), ...) tentaria chamar dobro antes, sem o argumento obrigatório valor.
Após executar o script, descreva o que os asserts e prints verificaram. Explique por que dobro, e não dobro(), foi passado para map. Por fim, justifique por que um objeto chamável é adequado aqui quando o contador e reiniciar fazem parte da interface.
Escreva pelo menos 180 caracteres (0/180).
Resumo
__call__ com argumentos por chamada, valor padrão e retorno calculado.map e materializei o resultado com list.assert para verificar retornos e mudanças de estado.callable indicaria que o objeto pode ser chamado, mas não validaria os argumentos nem garantiria que a execução terá sucesso.reiniciar, formam uma interface coerente.Parabéns! Você concluiu: Criar objetos chamáveis com __call__
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