
Dan
Solo estoy tratando de optimizar una de mis clases y he introducido algunas funciones en el mismo estilo que el patrón de diseño de peso mosca.
Sin embargo, estoy un poco confundido en cuanto a por qué __init__
siempre se llama después __new__
. No esperaba esto. ¿Alguien puede decirme por qué sucede esto y cómo puedo implementar esta funcionalidad de otra manera? (Aparte de poner la implementación en el __new__
que se siente bastante hacky.)
Aquí hay un ejemplo:
class A(object):
_dict = dict()
def __new__(cls):
if 'key' in A._dict:
print "EXISTS"
return A._dict['key']
else:
print "NEW"
return super(A, cls).__new__(cls)
def __init__(self):
print "INIT"
A._dict['key'] = self
print ""
a1 = A()
a2 = A()
a3 = A()
Salidas:
NEW
INIT
EXISTS
INIT
EXISTS
INIT
¿Por qué?
Utilizar __new__
cuando necesite controlar la creación de una nueva instancia.
Utilizar
__init__
cuando necesite controlar la inicialización de una nueva instancia.
__new__
es el primer paso de la creación de instancias. Se llama primero y es responsable de devolver una nueva instancia de su clase.
A diferencia de,
__init__
no devuelve nada; solo es responsable de inicializar la instancia después de que se haya creado.
En general, no debería necesitar anular __new__
a menos que esté subclasificando un tipo inmutable como str, int, unicode o tuple.
De la publicación de abril de 2008: Cuándo usar __new__
contra __init__
? en mail.python.org.
Debes considerar que lo que estás tratando de hacer generalmente se hace con un Fábrica y esa es la mejor manera de hacerlo. Utilizando __new__
no es una buena solución limpia, así que considere el uso de una fábrica. Aquí hay un buen ejemplo: ActiveState Fᴀᴄᴛᴏʀʏ ᴘᴀᴛᴛᴇʀɴ Receta.

vartec
__new__
es un método de clase estático, mientras que __init__
es un método de instancia.
__new__
tiene que crear la instancia primero, entonces __init__
puede inicializarlo. Tenga en cuenta que __init__
toma self
como parámetro. Hasta que crees una instancia, no hay self
.
Ahora, supongo, que estás tratando de implementar patrón único en Python. Hay algunas maneras de hacer eso.
Además, a partir de Python 2.6, puede usar la clase decoradores.
def singleton(cls):
instances = {}
def getinstance():
if cls not in instances:
instances[cls] = cls()
return instances[cls]
return getinstance
@singleton
class MyClass:
...
En la mayoría de los lenguajes orientados a objetos más conocidos, una expresión como SomeClass(arg1, arg2)
asignará una nueva instancia, inicializará los atributos de la instancia y luego la devolverá.
En la mayoría de los lenguajes orientados a objetos más conocidos, la parte “iniciar los atributos de la instancia” se puede personalizar para cada clase definiendo un constructor, que básicamente es solo un bloque de código que opera en la nueva instancia (usando los argumentos proporcionados a la expresión del constructor) para configurar las condiciones iniciales que se deseen. En Python, esto corresponde a la clase’ __init__
método.
de pitón __new__
es nada más y nada menos que una personalización similar por clase de la parte “asignar una nueva instancia”. Por supuesto, esto le permite hacer cosas inusuales, como devolver una instancia existente en lugar de asignar una nueva. Entonces, en Python, no deberíamos pensar en esta parte como algo que implica necesariamente la asignación; todo lo que requerimos es que __new__
se le ocurre una instancia adecuada de alguna parte.
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__
) después ya veces no. Si quieres ese comportamiento, tienes que decirlo explícitamente.
A menudo, puede refactorizar para que solo necesite __new__
o por lo que no necesita __new__
o para que __init__
se comporta de manera diferente en un objeto ya inicializado. Pero si realmente lo desea, Python le permite redefinir “el trabajo”, de modo que SomeClass(arg1, arg2)
no necesariamente llama __new__
seguido por __init__
. Para hacer esto, necesita crear una metaclase y definir su __call__
método.
Una metaclase es solo la clase de una clase. Y una clase’ __call__
El método controla lo que sucede cuando llamas a instancias de la clase. entonces un metaclase‘ __call__
El método controla lo que sucede cuando llamas a una clase; es decir, te permite redefinir el mecanismo de creación de instancias de principio a fin. Este es el nivel en el que puede implementar con mayor elegancia un proceso de creación de instancias completamente no estándar, como el patrón singleton. De hecho, con menos de 10 líneas de código puedes implementar un Singleton
metaclase que ni siquiera requiere que juegues con __new__
en absolutoy puede girar ninguna clase por lo demás normal en un singleton simplemente agregando __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 para esta situación!

gris
Para citar el documentación:
Las implementaciones típicas crean una nueva instancia de la clase invocando el método __new__() de la superclase usando “super(currentclass, cls).__new__(cls[, …])” con los argumentos apropiados y luego modificando la instancia recién creada según sea necesario antes de devolverla.
…
Si __new__() no devuelve una instancia de cls, entonces no se invocará el método __init__() de la nueva instancia.
__new__() está diseñado principalmente para permitir subclases de tipos inmutables (como int, str o tuple) para personalizar la creación de instancias.
Me doy cuenta de que esta pregunta es bastante antigua, pero tuve un problema similar. Lo siguiente hizo lo que quería:
class Agent(object):
_agents = dict()
def __new__(cls, *p):
number = p[0]
if not number in cls._agents:
cls._agents[number] = object.__new__(cls)
return cls._agents[number]
def __init__(self, number):
self.number = number
def __eq__(self, rhs):
return self.number == rhs.number
Agent("a") is Agent("a") == True
Usé esta página como un recurso. http://infohost.nmt.edu/tcc/help/pubs/python/web/new-new-method.html
Cuándo __new__
devuelve una instancia de la misma clase, __init__
se ejecuta después en el objeto devuelto. es decir, NO puedes usar __new__
para prevenir __init__
de ser ejecutado. Incluso si devuelve un objeto creado previamente desde __new__
será doble (triple, etc…) inicializado por __init__
una y otra vez.
Aquí está el enfoque genérico del patrón Singleton que amplía la respuesta de vartec anterior y la corrige:
def SingletonClass(cls):
class Single(cls):
__doc__ = cls.__doc__
_initialized = False
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Single, cls).__new__(cls, *args, **kwargs)
return cls._instance
def __init__(self, *args, **kwargs):
if self._initialized:
return
super(Single, self).__init__(*args, **kwargs)
self.__class__._initialized = True # Its crucial to set this variable on the class!
return Single
La historia completa es aquí.
Otro enfoque, que de hecho implica __new__
es usar métodos de clase:
class Singleton(object):
__initialized = False
def __new__(cls, *args, **kwargs):
if not cls.__initialized:
cls.__init__(*args, **kwargs)
cls.__initialized = True
return cls
class MyClass(Singleton):
@classmethod
def __init__(cls, x, y):
print "init is here"
@classmethod
def do(cls):
print "doing stuff"
Preste atención, que con este enfoque necesita decorar TODOS sus métodos con @classmethod
porque nunca usarás ninguna instancia real de MyClass
.

PMN
Creo que la respuesta simple a esta pregunta es que, si __new__
devuelve un valor que es del mismo tipo que la clase, el __init__
la función se ejecuta, de lo contrario no lo hará. En este caso, su código devuelve A._dict('key')
que es de la misma clase que cls
entonces __init__
será ejecutado.
También estaba tratando de entender el patrón de diseño, y la primera vez que escuché sobre: el patrón de diseño de peso ligero … y un enlace muy bueno que tiene un ejemplo en casi todos los idiomas populares.
– Emma Y.
7 mayo 2020 a las 22:10
¿No es un singleton?
– Derek
13 de marzo de 2021 a las 19:07