¿Cuál es una forma limpia y pythonica de tener múltiples constructores en Python?

Requisito previo: constructores , @classmethod decoradores

Python no admite constructores múltiples explícitos, sin embargo, hay algunas formas en que se pueden lograr los constructores múltiples. Si se escriben varios métodos __init__ para la misma clase, el último sobrescribe todos los constructores anteriores. Mira el ejemplo de abajo.

Python3

class example:
  
    def __init__(self):
        print("One")
  
    def __init__(self):
        print("Two")
  
    def __init__(self):
        print("Three")
  
  
e = example()
Producción

Three

Necesidad de múltiples constructores

Se requieren múltiples constructores cuando uno tiene que realizar diferentes acciones en la instanciación de una clase. Esto es útil cuando la clase tiene que realizar diferentes acciones en diferentes parámetros. Los constructores de clases se pueden hacer para exhibir polimorfismo de tres maneras que se enumeran a continuación.

  1. Sobrecarga de constructores basados ​​en argumentos.
  2. Llamar a métodos desde __init__ .
  3. Usando el decorador @classmethod .

Este artículo explica cómo tener múltiples constructores de una manera limpia y pythonica con ejemplos.

Sobrecarga de constructores basados ​​en argumentos

La sobrecarga del constructor se realiza comprobando las condiciones de los argumentos pasados ​​y realizando las acciones requeridas. Por ejemplo, considere pasar un argumento a la clase muestra

  • Si el parámetro es un int , el cuadrado del número debería ser la respuesta.
  • Si el parámetro es una string , la respuesta debe ser «¡¡Hola!!» + string.
  • Si el parámetro tiene una longitud superior a 1, la suma de los argumentos debe almacenarse como respuesta.

Python3

class sample:
  
    # constructor overloading
    # based on args
    def __init__(self, *args):
  
        # if args are more than 1
        # sum of args
        if len(args) > 1:
            self.ans = 0
            for i in args:
                self.ans += i
  
        # if arg is an integer
        # square the arg
        elif isinstance(args[0], int):
            self.ans = args[0]*args[0]
  
        # if arg is string
        # Print with hello
        elif isinstance(args[0], str):
            self.ans = "Hello! "+args[0]+"."
  
  
s1 = sample(1, 2, 3, 4, 5)
print("Sum of list :", s1.ans)
  
s2 = sample(5)
print("Square of int :", s2.ans)
  
s3 = sample("GeeksforGeeks")
print("String :", s3.ans)
Producción

Sum of list : 15
Square of int : 25
String : Hello! GeeksforGeeks.

En el código anterior, la variable de instancia era ans , pero sus valores difieren según los argumentos. Dado que hay un número variable de argumentos para la clase, se usa *args , que es una tupla que contiene los argumentos pasados ​​y se puede acceder mediante un índice. En el caso de int y string, solo se pasa un argumento y, por lo tanto, se accede como args[0] (el único elemento en la tupla).

Llamar a métodos desde __init__

Una clase puede tener un constructor __init__ que puede realizar cualquier acción cuando se crea la instancia de la clase. Este constructor se puede hacer para diferentes funciones que realizan diferentes acciones en función de los argumentos pasados. Ahora considere un ejemplo: 

  • Si el número de argumentos pasados ​​es 2, entonces evalúe la expresión x = a 2 -b 2
  • Si el número de argumentos pasados ​​es 3, entonces evalúe la expresión y = a 2 +b 2 -c.
  • Si se han pasado más de 3 argumentos, sume los cuadrados y divídalos por el valor más alto de los argumentos pasados.

Python3

class eval_equations:
  
  # single constructor to call other methods
    def __init__(self, *inp):
  
        # when 2 arguments are passed
        if len(inp) == 2:
            self.ans = self.eq2(inp)
  
        # when 3 arguments are passed
        elif len(inp) == 3:
            self.ans = self.eq1(inp)
  
        # when more than 3 arguments are passed
        else:
            self.ans = self.eq3(inp)
  
    def eq1(self, args):
        x = (args[0]*args[0])+(args[1]*args[1])-args[2]
        return x
  
    def eq2(self, args):
        y = (args[0]*args[0])-(args[1]*args[1])
        return y
  
    def eq3(self, args):
        temp = 0
        for i in range(0, len(args)):
            temp += args[i]*args[i]
          
        temp = temp/max(args)
        z = temp
        return z
  
  
inp1 = eval_equations(1, 2)
inp2 = eval_equations(1, 2, 3)
inp3 = eval_equations(1, 2, 3, 4, 5)
  
print("equation 2 :", inp1.ans)
print("equation 1 :", inp2.ans)
print("equation 3 :", inp3.ans)
Producción

equation 2 : -3
equation 1 : 2
equation 3 : 11.0

 En el ejemplo anterior, la ecuación a evaluar se escribe en diferentes métodos de instancia y se hace para devolver la respuesta. El constructor llama al método apropiado y actúa de manera diferente para diferentes parámetros.

Las expresiones han sido evaluadas de la siguiente manera:

entradas : 1,2 —> 1 2 -2 2 = 1-4 = -3

entradas : 1,2,3 —> (1 2 +2 2 ) – 3 = 5-3 = 2

entradas : 1,2,3,4,5 —> (1 2 + 2 2 + 3 2 + 4 2 + 5 2 ) / 5 = 55/5 = 11.0

Usando el decorador @classmethod

Este decorador permite que una función sea accesible sin instanciar la clase. Se puede acceder a las funciones tanto por la instancia de la clase como por la propia clase. El primer parámetro del método que se declara como classmethod es cls, que es como el self de los métodos de instancia. Aquí cls se refiere a la clase misma. Esto demuestra ser muy útil para usar múltiples constructores en Python y es un enfoque más pythonico que los anteriores. Considere el mismo ejemplo utilizado anteriormente. Evaluar diferentes expresiones basadas en el número de entradas.

Python3

class eval_equations:
  
    # basic constructor
    def __init__(self, a):
        self.ans = a
  
    # expression 1
    @classmethod
    def eq1(cls, args):
        
      # create an object for the class to return
        x = cls((args[0]*args[0])+(args[1]*args[1])-args[2])
        return x
  
    # expression 2
    @classmethod
    def eq2(cls, args):
        y = cls((args[0]*args[0])-(args[1]*args[1]))
        return y
  
    # expression 3
    @classmethod
    def eq3(cls, args):
        temp = 0
  
        # square of each element
        for i in range(0, len(args)):
            temp += args[i]*args[i]
  
        temp = temp/max(args)
        z = cls(temp)
        return z
  
  
li = [[1, 2], [1, 2, 3], [1, 2, 3, 4, 5]]
i = 0
  
# loop to get input three times
while i < 3:
  
    inp = li[i]
  
    # no.of.arguments = 2
    if len(inp) == 2:
        p = eval_equations.eq2(inp)
        print("equation 2 :", p.ans)
  
    # no.of.arguments = 3
    elif len(inp) == 3:
        p = eval_equations.eq1(inp)
        print("equation 1 :", p.ans)
  
    # More than three arguments
    else:
        p = eval_equations.eq3(inp)
        print("equation 3 :", p.ans)
  
    #increment loop        
    i += 1
Producción

equation 2 : -3
equation 1 : 2
equation 3 : 11.0

En el ejemplo anterior, la instancia del objeto no se crea inicialmente. Los métodos de clase para evaluar varias expresiones se han definido con el decorador @classmethod . Ahora se pueden llamar con el nombre de la clase y el objeto se crea en ese método de clase después de evaluar la expresión. La variable de instancia contiene diferentes respuestas para un número diferente de parámetros pasados.

Publicación traducida automáticamente

Artículo escrito por erakshaya485 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *