En la mayoría de los lenguajes OO conocidos, una expresión como SomeClass(arg1, arg2)
asignará una nueva instancia, inicializará los atributos de la instancia y luego la devolverá.
En lenguajes orientados a objetos más conocidos, la parte "inicializar atributos de la instancia" se pueden personalizar para cada clase mediante la definición de un constructor, que es básicamente un bloque de código que funciona en la nueva instancia (utilizando el argumentos proporcionados a la expresión del constructor) para configurar las condiciones iniciales deseadas. En Python, esto corresponde al método de clase '__init__
.
Python's __new__
es nada más y nada menos que la personalización por clase similar de la parte "asignar una nueva instancia". Esto, por supuesto, le permite hacer cosas inusuales, como devolver una instancia existente en lugar de asignar una nueva. Entonces, en Python, realmente no deberíamos pensar que esta parte necesariamente involucre asignación; todo lo que necesitamos es que __new__
encuentre una instancia adecuada de algún lado.
Pero todavía es solo la mitad del trabajo, y no hay forma de que el sistema Python sepa que a veces desea ejecutar la otra mitad del trabajo (__init__
) posteriormente y otras veces no. Si quieres ese comportamiento, tienes que decirlo explícitamente.
A menudo, puede refactorizar lo que sólo necesita __new__
, o por lo que no necesita __new__
, o para que __init__
comporta de manera diferente en un objeto inicializado ya. Pero si realmente lo desea, Python realmente le permite redefinir "el trabajo", de modo que SomeClass(arg1, arg2)
no necesariamente llame al __new__
seguido de __init__
. Para hacer esto, debe crear una metaclase y definir su método __call__
.
Una metaclase es solo la clase de una clase. Y el método de clase __call__
controla lo que ocurre cuando llamas a las instancias de la clase. Entonces, un método de metaclass '__call__
controla lo que ocurre cuando se llama a una clase; es decir, le permite redefinir el mecanismo de creación de instancias de principio a fin. Este es el nivel en el que puede implementar de forma más elegante un proceso de creación de instancia completamente no estándar, como el patrón singleton. De hecho, con menos de 10 líneas de código se puede implementar una metaclase Singleton
que entonces ni siquiera requiere que Futz con __new__
en absoluto, y puede convertir cualquier clase de otro modo normal en un producto único, simplemente añadiendo __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
Sin embargo, esta es probablemente una magia más profunda de lo que realmente se justifica en esta situación.
¿Qué pasa con esto? ¿Qué estás tratando de lograr que esto no ocurra todavía? Además, ¿por qué tener un ítem 1 ítem? –