El método __init__
no es realmente el constructor de la clase, es el inicializador de la clase (__init__
) y es llamado automáticamente cuando se instancia dicha clase si el verdadero constructor (__new__
) retorna una instancia válida de la clase.
Por tanto, llamar a __init__
directamente no genera una instancia de la clase (trabajo de __new__
), el inicializador a grandes rasgos permite definir un estado inicial para una instancia de la clase previamente existente generada por __new__
.
Por lo general a __init__
no se le llama directamente de forma explícita excepto en casos especiales, quizás el más común es la herencia en la que sobrescribimos el método __init__
en una clase hija pero queremos que el inicializador del padre o padres sea llamado también:
class Padre:
def __init__(self):
print("Inicializador de Padre llamado")
self.foo = 4
class Hija(Padre):
def __init__(self):
# Sobrescribimos el __init__ heredado de Padre
print("Inicializador de Hija llamado")
>>> hija = Hija()
Inicializador de Hija llamado
>>> hija.foo
AttributeError: 'Hija' object has no attribute 'foo'
Como vemos el inicializador del padre ha sido solapado por el del hijo, esto hace que no sea llamado y por tanto el atributo foo
no existe en la instancia de Hija
. Si queremos que el inicializador del padre sea llamado si ha sido sobrescrito en la clase hija, debemos hacerlo de forma explícita:
class Padre:
def __init__(self):
print("Inicializador de Padre llamado")
self.foo = 4
class Hija(Padre):
def __init__(self):
# Sobrescribimos el __init__ heredado de Padre
Padre.__init__(self)
print("Inicializador de Hija llamado")
>>> hija = Hija()
Inicializador de Padre llamado
Inicializador de Hija llamado
>>> hija.foo
4
Aunque es recomendable usar super
para esto:
super().__init__()
En tu caso, por tanto, simplemente instancia la clase y pasa los tres argumentos:
Range(comienzo, fin, paso)
El error se debe a que el inicializador recibe realmente cuatro parámetros, siendo el primero como en cualquier método de instancia la referencia a la propia instancia de la clase a la que pertenece el método, por convención se nombra con self
(aunque técnicamente podemos llamarlo como quramos). Este parámetro se pasa de forma automática al llamar a cualquier método de instancia que sea llamado mediante una referencia a una instancia de la clase, incluido el inicializador. Tu lo llamas a través de una referencia a la clase, no a una instancia de la misma, por lo que self
(instancia) ni existe ni se pasa de forma automática por tanto.
El método tal como lo llamas recibe los siguientes argumentos realmente:
Rango.__init__(self=comienzo, start=fin, end=paso)
por lo que a step
no se le asigna nada y de ahí el error que te muestra.
Para más información mirate estas dos preguntas:
Por otro lado, tienes otras inconsistencias en tu clase:
Presupongo que intentas implementar algo parecido a range
de Python 2.x, en tal caso y siguiendo un poco tu propia idea podrías hacer algo así (muy simplificado):
class Range:
def __init__(self, start, end, step):
self.start = start
self.end = end
self.step = step
self.lista = []
self.item = self.start
while self.item < self.end:
self.lista.append(self.item)
self.item += self.step
def __len__(self):
return len(self.lista)
def __getitem__(self, elemento):
return self.lista[elemento]
comienzo = int(input("Introduce el valor de inicio\n"))
fin = int(input("Introduce la cota superior\n"))
paso = int(input("Introduce el espacio entre pasos\n"))
rango = Range(comienzo, fin, paso)
Introduce el valor de inicio
3
Introduce la cota superior
16
Introduce el espacio entre pasos
2
>>> for item in rango:
print(item)
3
5
7
9
11
13
15
>>> rango[4]
11
>>> len(rango)
7