Curso de introducción a la programación con Python¶

    Autor: Luis Fernando Apáez Álvarez
    -Curso PyM-
    Proyecto 1 (parte II)
    Fecha: 01 de diciembre del 2022


In [ ]:
# Paquetes que ocuparemos en esta parte del proyecto
import matplotlib.pyplot as mplot
import numpy as np

En la parte final de la primer parte de este proyecto probamos nuestro código creando el objeto prueba, donde ejecutamos el código

# Instanciamos la clase
prueba = graficar()

# Invocamos el método str
print(prueba.mensaje_inicial())

# Información dle usuario (proviene de la clase menu)
prueba.info_usuario()

# Método str (proviene de la clase graficar)
print(prueba)

# Graficamos (proviene de la clase graficar)
prueba.Graficador()

ejecutando dicho código en ese orden. Para este punto podemos notar que requerimos de cierto control de flujo en nuestras clases pues, como vemos en el código anterior, debemos primero ejecuar print(prueba.mensaje_inicial()) y prueba.info_usuario() para que el resto del código funcione; asimismo, lo último que debe ejecutarse es el método Graficador(), pues de ejecutarse antes causará un error. Comenzaremos implementando primero un control de flujo en la clase graficar, donde por ejemplo desearemos que el método str deba ejecutarse primero antes que el métodoGraficador().

Lo que haremos será definir un atributo con un valor lógico con el cual estableceremos el correcto control de flujo a la hora de llamar a los métodos de esta clase:

In [4]:
class graficar(menu):
    def __init__(self):
        super().__init__()
        
        # Atributo lógico para el control de flujo
        self.control_f = False 
        
    def __str__(self):
        # Cambiamos el valor lógico para poder ejecutar 
        # el return de este método
        self.control_f = True
        
        return f'Rango:({self.rango_inf},{self.rango_sup})\nf(x) = {self.fun}'
    
    def Graficador(self):
        if self.control_f:
            x = np.arange(eval(self.rango_inf), eval(self.rango_sup), 0.01)
            y = self.fun
            mplot.plot(x, eval(y))
            mplot.grid()
            mplot.show()
        else:
            print("Debe ejecutarse primero el método str!")

lo anterior puede explicarse como:

  • De forma inicial self.control_f=False de tal manera, si invocamos el método Graficador() antes del método str, self.control_f seguirá siendo falso. Por ende, debido al if, se imprimirá el mensaje "Debe ejecutarse primero el método str!".

  • Al invocar primero el método str cambiamos el valor de self.control_f a verdadero, de modo que, después de invocar el método str, podremos invocar el método Graficador() de forma correcta.

Hagamos una prueba:

In [8]:
# Instanciamos la clase e ingresamos la información del usuario

prueba = graficar()
prueba.info_usuario()
______________________________
In [9]:
# Invocamos el método Graficador antes del str
prueba.Graficador()
Debe ejecutarse primero el método str!
In [10]:
# Correcto control de flujo:

# Invocamos primero el método str
print(prueba)

# Graficamos (proviene de la clase graficar)
prueba.Graficador()
Rango:(0,1)
f(x) = x**2

Ahora bien, adaptaremos también la clase menu para adaptar un control de flujo con el siguiente orden:

  1. Debe invocarse primero el método mensaje_inicial
  2. Debe invocarse el método info_usuario
  3. Debe invocarse el método str de la clase graficar
  4. Al final, debe invocarse el método Graficador()

La idea para implementar lo anterior es análoga a lo que hicimos antes, salvo que el atributo self.control_f será parte del constructor de la super clase.

Así, escribimos

In [31]:
class menu:
    def __init__(self):
        self.fun = ""
        self.rango = ""
        
        # Atributo para control de flujo
        self.control_f = False

    def mensaje_inicial(self):
        self.cadena1 = "De que tipo es tu función:"
        self.cadena2 = "_" * 30
        self.cadena3 = "1: Algebraicas"
        self.cadena4 = "2: Trigonométricas"
        self.cadena5 = "3: Exponencial"
        self.cadena6 = "4: Logarítmica"
        self.cadena7 = "_" * 30
        
        # Cambiamos valor lógico de control_f
        self.control_f = True
        
        return self.cadena1 + "\n" + self.cadena2 + "\n" + self.cadena3 \
    + "\n" + self.cadena4 + "\n" + self.cadena5 + "\n" + self.cadena6 \
    + "\n" + self.cadena7
    
    def info_usuario(self):
        
        # Implementamos el if para el control del flujo
        if self.control_f:
            self.n_aux = input("Coloca un número del 1 al 4: ")
            print("_" * 30)
            if int(self.n_aux) not in (1,2,3,4):
                print("Error, debes ingresar un número del 1 al 4")
                print("Fin del proceso")
            else:
                self.fun = input("Ingresa tu función: ")
                self.rango = input("Ingresa el rango de graficación: ")
                self.rango_inf = self.rango[self.rango.find("(") + 1: self.rango.find(",")]
                self.rango_sup = self.rango[self.rango.find(",") + 1: self.rango.find(")")]
            if int(self.n_aux) != 1:
                self.fun = "np." + self.fun
            else:
                self.fun = self.fun
        else:
            print("Debe invocarse primero el método mensaje inicial")

Notemos que al invocar el método info_usuario() de la clase menú, tendremos que self.control_f tendrá asignado el valor de True. Así, el control del flujo de la clase graficar() se verá afectado y podremos invocar el método Graficador() antes del método str. Para resolver este conflicto escribimos

In [37]:
class graficar(menu):
    def __init__(self):
        super().__init__()
        # Cambiamos nuevamente el valor lógico de control_f
        
    def __str__(self):
        # Cambiamos el valor lógico para poder ejecutar 
        # el return de este método
        self.control_f = False
        
        return f'Rango:({self.rango_inf},{self.rango_sup})\nf(x) = {self.fun}'
    
    def Graficador(self):
        if not self.control_f:
            x = np.arange(eval(self.rango_inf), eval(self.rango_sup), 0.01)
            y = self.fun
            mplot.plot(x, eval(y))
            mplot.grid()
            mplot.show()
        else:
            print("Debe ejecutarse primero el método str!")

es decir, como self.control_f tiene asignado el valor True, el método Graficador() sólo se ejecutará si self.control_f es False. Luego, el método str lo que hace es cambiar el valor de True de control_f a False, con lo cual conseguimos el control de flujo deseado. Hagamos unas pruebas:

In [38]:
# Invocamos primero el método info_usuario antes del mensaje_inicial
prueba = graficar()
prueba.info_usuario()
Debe invocarse primero el método mensaje inicial
In [39]:
# Correcto control de flujo en la clase Menu
print(prueba.mensaje_inicial())
prueba.info_usuario()
De que tipo es tu función:
______________________________
1: Algebraicas
2: Trigonométricas
3: Exponencial
4: Logarítmica
______________________________
______________________________

Probamos ahora el control de flujo en la clase graficar()

In [41]:
# Invocamos el método graficar antes que el str
prueba.Graficador()
Debe ejecutarse primero el método str!
In [42]:
# Correcto control de flujo
print(prueba)
prueba.Graficador()
Rango:(0,1)
f(x) = x**2

Para finalizar esta parte del proyecto grafiquemos las siguientes funciones

In [44]:
# Instanciamos la clase
prueba2 = graficar()

# Invocamos el método str
print(prueba2.mensaje_inicial())

# Información dle usuario (proviene de la clase menu)
prueba2.info_usuario()

# Método str (proviene de la clase graficar)
print(prueba2)

# Graficamos (proviene de la clase graficar)
prueba2.Graficador()
De que tipo es tu función:
______________________________
1: Algebraicas
2: Trigonométricas
3: Exponencial
4: Logarítmica
______________________________
______________________________
Rango:(-np.pi,np.pi)
f(x) = np.cos(x)
In [45]:
# Instanciamos la clase
prueba3 = graficar()

# Invocamos el método str
print(prueba3.mensaje_inicial())

# Información dle usuario (proviene de la clase menu)
prueba3.info_usuario()

# Método str (proviene de la clase graficar)
print(prueba3)

# Graficamos (proviene de la clase graficar)
prueba3.Graficador()
De que tipo es tu función:
______________________________
1: Algebraicas
2: Trigonométricas
3: Exponencial
4: Logarítmica
______________________________
______________________________
Rango:(1,5)
f(x) = np.log(x)