Estoy tratando de comprender cómo deberían crearse nuevas instancias de una clase Python cuando el proceso de creación puede ser mediante el constructor o mediante el método __new__
. En particular, observo que cuando se utiliza el constructor, el método __init__
se llamará automáticamente después de __new__
, mientras que al invocar __new__
directamente no se llamará automáticamente a la clase __init__
. Puedo forzar que se llame a __init__
cuando se llama explícitamente __new__
incrustando una llamada al __init__
dentro de __new__
, pero luego __init__
terminará recibiendo llamadas dos veces cuando la clase se crea mediante el constructor.Asegurando que __init__ solo se invoque una vez cuando el constructor crea una instancia de clase o __new__
Por ejemplo, considere la siguiente clase de juguete, que almacena una propiedad interna, es decir, un objeto list
llamado data
: es útil considerarlo como el inicio de una clase vectorial.
class MyClass(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
return obj
def __init__(self, data):
self.data = data
def __getitem__(self, index):
return self.__new__(type(self), self.data[index])
def __repr__(self):
return repr(self.data)
una nueva instancia de la clase se pueden crear utilizando el constructor (en realidad no sé si eso es la terminología correcta en Python), algo así como
x = MyClass(range(10))
o mediante corte en rodajas, la cual se puede ver invoca una llamada al __new__
en el método __getitem__
.
x2 = x[0:2]
En el primer caso, __init__
se llamará dos veces (tanto a través de la llamada explícita dentro de __new__
y luego de nuevo automáticamente), y una vez en el segundo ejemplo. Obviamente, solo me gustaría llamar al __init__
una vez en cualquier caso. ¿Hay una forma estándar de hacer esto en Python?
Tenga en cuenta que en mi ejemplo que podía deshacerse del método __new__
y redefinir __getitem__
como
def __getitem__(self, index):
return MyClass(self.data[index])
pero entonces esto podría causar un problema si más adelante quiero heredar de MyClass
, porque si hago una llamada como child_instance[0:2]
, obtendré una instancia de MyClass
, no la clase secundaria.
Gracias por la descripción detallada @unutbu. – Abiel
Esto es engañoso. Primero, '__new__' no llama a' __init__' y luego devuelve la instancia. '__new__' se llama para crear una instancia, luego' __init__' se invoca en lo que '__new__' devolvió. Esta es la razón por la cual invocar '__new__' directamente no llama a' __init__'. En segundo lugar, '__new__' no se parece en nada a un constructor, y no debería llamarse uno. '__init__' se llama constructor en los documentos oficiales de Python. – Ben
@Ben, ¿tiene una referencia de los documentos de python? Parece que aclararía un montón de debate sobre si '__init__' es un constructor ... https://stackoverflow.com/questions/6578487/init-as-a-constructor – pylang