Na maioria das linguagens OO conhecidas, uma expressão como SomeClass(arg1, arg2)
alocará uma nova instância, inicializará os atributos da instância e a retornará.
Na maioria das linguagens OO conhecidas, a parte "inicializar os atributos da instância" pode ser personalizada para cada classe, definindo um construtor , que é basicamente apenas um bloco de código que opera na nova instância (usando os argumentos fornecidos para a expressão do construtor ) para configurar as condições iniciais desejadas. No Python, isso corresponde ao __init__
método da classe .
O Python __new__
não é nada mais e nada menos que a customização por classe semelhante da parte "alocar uma nova instância". É claro que isso permite que você faça coisas incomuns, como retornar uma instância existente, em vez de alocar uma nova. Portanto, em Python, não devemos realmente pensar nessa parte como necessariamente envolvendo alocação; tudo o que exigimos é que __new__
surja uma instância adequada de algum lugar.
Mas ainda é apenas metade do trabalho, e não há como o sistema Python saber que às vezes você deseja executar a outra metade do trabalho ( __init__
) depois e às vezes não. Se você deseja esse comportamento, deve dizê-lo explicitamente.
Freqüentemente, você pode refatorar para que você só precise __new__
ou não precise __new__
, ou que __init__
se comporte de maneira diferente em um objeto já inicializado. Mas se você realmente quiser, o Python realmente permite que você redefina "o trabalho", de modo que SomeClass(arg1, arg2)
não necessariamente chame __new__
seguido por __init__
. Para fazer isso, você precisa criar uma metaclasse e definir sua__call__
método.
Uma metaclasse é apenas a classe de uma classe. E o __call__
método de uma classe controla o que acontece quando você chama instâncias da classe. Portanto , o método de uma metaclasse__call__
controla o que acontece quando você chama uma classe; isto é, permite redefinir o mecanismo de criação da instância do início ao fim . Esse é o nível no qual você pode implementar com mais elegância um processo de criação de instância completamente fora do padrão, como o padrão singleton. Na verdade, com menos de 10 linhas de código que você pode implementar uma Singleton
metaclasse que, em seguida, nem sequer exigem que você futz com __new__
em tudo , e pode transformar qualquer classe de outra forma normal em um singleton simplesmente adicionando __metaclass__ = Singleton
!
class Singleton(type):
def __init__(self, *args, **kwargs):
super(Singleton, self).__init__(*args, **kwargs)
self.__instance = None
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(Singleton, self).__call__(*args, **kwargs)
return self.__instance
No entanto, essa provavelmente é uma mágica mais profunda do que realmente é necessária para esta situação!