Eu sei que o __call__
método em uma classe é acionado quando a instância de uma classe é chamada. No entanto, não tenho idéia de quando posso usar esse método especial, porque é possível simplesmente criar um novo método e executar a mesma operação feita no __call__
método. Em vez de chamar a instância, você pode chamar o método.
Eu realmente aprecio isso se alguém me der um uso prático desse método especial.
python
methods
call
magic-methods
mohi666
fonte
fonte
__call__
está oculto à vista de todos; é como você instancia uma classe:x = Foo()
é realmentex = type(Foo).__call__(Foo)
, onde__call__
é definido pela metaclasse deFoo
.Respostas:
O módulo de formulários do Django usa o
__call__
método para implementar uma API consistente para validação de formulários. Você pode escrever seu próprio validador para um formulário no Django como uma função.O Django possui alguns validadores internos padrão, como validadores de email, validadores de URL, etc., que são amplamente abrangidos pelos validadores RegEx. Para implementar isso de maneira limpa, o Django recorre a classes que podem ser chamadas (em vez de funções). Ele implementa a lógica padrão de Validação de Regex em um RegexValidator e, em seguida, estende essas classes para outras validações.
Agora, sua função personalizada e o EmailValidator interno podem ser chamados com a mesma sintaxe.
Como você pode ver, essa implementação no Django é semelhante ao que outros explicaram em suas respostas abaixo. Isso pode ser implementado de qualquer outra maneira? Você poderia, mas IMHO não será tão legível nem tão facilmente extensível para uma grande estrutura como o Django.
fonte
Este exemplo usa memorização , basicamente armazenando valores em uma tabela (neste caso, dicionário) para que você possa procurá-los mais tarde, em vez de recalculá-los.
Aqui, usamos uma classe simples com um
__call__
método para calcular fatoriais (por meio de um objeto que pode ser chamado ) em vez de uma função fatorial que contém uma variável estática (como isso não é possível no Python).Agora você tem um
fact
objeto que pode ser chamado, assim como todas as outras funções. Por exemploE também é com estado.
fonte
fact
objeto indexável, pois sua__call__
função é essencialmente um índice. Também usaria uma lista em vez de um ditado, mas sou apenas eu.__call__
, ser simples e nada mais.Acho útil, pois me permite criar APIs fáceis de usar (você tem algum objeto que requer alguns argumentos específicos) e é fácil de implementar porque é possível usar práticas orientadas a objetos.
A seguir, é o código que escrevi ontem, que cria uma versão dos
hashlib.foo
métodos que misturam arquivos inteiros em vez de seqüências de caracteres:Esta implementação me permite usar as funções de maneira semelhante às
hashlib.foo
funções:É claro que eu poderia ter implementado de uma maneira diferente, mas, neste caso, parecia uma abordagem simples.
fonte
__call__
você fornece uma ferramenta que permite usar técnicas de OO para resolver problemas.isinstance
ou algo semelhante.__call__
método em vez de um fechamento é quando você está lidando com o módulo de multiprocessamento, que usa decapagem para passar informações entre processos. Você não pode selecionar um fechamento, mas pode selecionar uma instância de uma classe.__call__
também é usado para implementar classes decoradoras em python. Nesse caso, a instância da classe é chamada quando o método com o decorador é chamado.fonte
Sim, quando você sabe que está lidando com objetos, é perfeitamente possível (e em muitos casos aconselhável) usar uma chamada de método explícita. No entanto, às vezes você lida com código que espera objetos que podem ser chamados - normalmente funciona, mas graças a
__call__
você pode criar objetos mais complexos, com dados de instância e mais métodos para delegar tarefas repetitivas, etc.Além disso, às vezes você está usando objetos para tarefas complexas (onde faz sentido escrever uma classe dedicada) e objetos para tarefas simples (que já existem em funções ou são mais facilmente escritas como funções). Para ter uma interface comum, é necessário escrever pequenas classes envolvendo essas funções com a interface esperada ou manter as funções das funções e tornar os objetos mais complexos que podem ser chamados. Vamos dar tópicos como exemplo. Os
Thread
objetos do módulo libary padrãothreading
querem uma chamada comotarget
argumento (ou seja, como ação a ser realizada no novo thread). Com um objeto que pode ser chamado, você não está restrito a funções, também pode passar outros objetos, como um trabalhador relativamente complexo que obtém tarefas para executar em outros encadeamentos e os executa sequencialmente:Este é apenas um exemplo, mas acho que já é complexo o suficiente para justificar a classe. Fazer isso apenas com funções é difícil, pelo menos requer o retorno de duas funções e isso está se tornando lentamente complexo. Um poderia mudar o nome
__call__
para outra coisa e passar por um método vinculado, mas que faz com que o código criando o fio um pouco menos óbvio, e não adiciona qualquer valor.fonte
__call__
usei instâncias de classe (em vez de funções) como aplicativos WSGI. Aqui está um exemplo de "The Definitive Guide to Pilões": Usando instâncias de classesDecoradores baseados em classe usam
__call__
para referenciar a função agrupada. Por exemplo:Há uma boa descrição das várias opções aqui em Artima.com
fonte
O
__call__
método IMHO e os fechamentos nos fornecem uma maneira natural de criar um padrão de design de ESTRATÉGIA em Python. Definimos uma família de algoritmos, encapsulamos cada um, os tornamos intercambiáveis e, no final, podemos executar um conjunto comum de etapas e, por exemplo, calcular um hash para um arquivo.fonte
Acabei de me deparar com um uso
__call__()
em conjunto com o__getattr__()
qual acho bonito. Ele permite ocultar vários níveis de uma API JSON / HTTP / (porém_serializada) dentro de um objeto.A
__getattr__()
parte cuida de retornar iterativamente uma instância modificada da mesma classe, preenchendo mais um atributo de cada vez. Depois que todas as informações tiverem sido esgotadas,__call__()
retomará os argumentos que você passou.Usando esse modelo, você pode, por exemplo, fazer uma chamada como
api.v2.volumes.ssd.update(size=20)
, que termina em uma solicitação PUT parahttps://some.tld/api/v2/volumes/ssd/update
.O código específico é um driver de armazenamento em bloco para um determinado back-end de volume no OpenStack, você pode conferir aqui: https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py
EDIT: Atualizado o link para apontar para a revisão principal.
fonte
Especifique
__metaclass__
ae substitua o__call__
método e faça com que o método das meta classes especificadas__new__
retorne uma instância da classe, viola, você tem uma "função" com os métodos.fonte
Podemos usar o
__call__
método para usar outros métodos de classe como métodos estáticos.fonte
Um exemplo comum é o
__call__
infunctools.partial
, aqui está uma versão simplificada (com Python> = 3.5):Uso:
fonte
O operador de chamada de função.
O método __call__ pode ser usado para redefinir / reinicializar o mesmo objeto. Também facilita o uso de instâncias / objetos de uma classe como funções, passando argumentos para os objetos.
fonte
I encontrar um bom lugar para usar objetos que podem ser chamados, aqueles que definem
__call__()
, é quando usando os recursos de programação funcional em Python, tais comomap()
,filter()
,reduce()
.O melhor momento para usar um objeto que pode ser chamado em uma função simples ou lambda é quando a lógica é complexa e precisa reter algum estado ou usar outras informações que não são passadas para a
__call__()
função.Aqui está um código que filtra nomes de arquivos com base em sua extensão de nome de arquivo usando um objeto que pode ser chamado e
filter()
.Callable:
Uso:
Resultado:
fonte
É tarde demais, mas estou dando um exemplo. Imagine que você tem uma
Vector
aula e umaPoint
aula. Ambos tomamx, y
como argumentos posicionais. Vamos imaginar que você queira criar uma função que mova o ponto a ser colocado no vetor.4 Soluções
put_point_on_vec(point, vec)
Crie um método na classe de vetor. por exemplo
my_vec.put_point(point)
Point
classe.my_point.put_on_vec(vec)
Vector
implementa__call__
, então você pode usá-lo comomy_vec_instance(point)
Na verdade, isso é parte de alguns exemplos nos quais estou trabalhando para obter um guia para métodos de dunder explicados com o Maths que lançarei mais cedo ou mais tarde.
Deixei a lógica de mudar o ponto em si, porque não é disso que se trata esta questão
fonte