2

Estoy dando mis primeros pasos en Python no entiendo porque el constructor no coge correctamente los parámetros, el código es el siguiente:

numeroElementos=1
lista=[]

class Range:

    def __init__(self, start, end, step):
        self.start = start
        self.end = end
        self.step = step
        lista = [self.start]
        if lista[numeroElementos-1] < self.end:
            lista[numeroElementos] = self.start + self.step        

    def __len__(self,lista):
       return numeroElementos

    def __getItem__(self,elemento):
       return lista[elemento-1]

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"))
Range.__init__(comienzo, fin, paso)

La consola arroja el siguiente error:

TypeError: __init__() missing 1 required positional argument: 'step'
ChemaCortes
  • 8,325
  • 18
  • 36
AdCerros
  • 168
  • 14

1 Answers1

3

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
FJSevilla
  • 55,603
  • 7
  • 35
  • 58