Crear aplicación gráfica con Python, MySQL y Tkinter – Parte 4 – 100 días de Python #29
Continuamos con la cuarta parte del proyecto. En esta ocasión, voy a mostrarte como crear métodos decoradores en clases Python. De esta forma, podremos reutilizar código repetitivo.
Así es como tenemos, de momento, la aplicación:
base_datos.py
import mysql.connector #conexion con la base de datos acceso_bd = {"host" : "localhost", "user" : "root", "password" : "programacionfacil", } class BaseDatos: #Conexión y cursor def __init__(self, **kwargs): self.conector = mysql.connector.connect(**kwargs) self.cursor = self.conector.cursor() #Consultas SQL def consulta(self, sql): self.cursor.execute(sql) return self.cursor #Mostrar bases de datos def mostrar_bd(self): self.cursor.execute("SHOW DATABASES") for bd in self.cursor: print(bd) #Eliminar bases de datos def eliminar_bd(self, nombre_bd): try: self.cursor.execute(f"DROP DATABASE {nombre_bd}") print(f"Se eliminó la base de datos {nombre_bd} correctamente.") except: print(f"Base de datos '{nombre_bd}' no encontrada.") print("Estas son las bases de datos que tiene el servidor:") self.mostrar_bd(self) #método para crear bases de datos def crear_bd(self, nombre_bd): try: self.cursor.execute(f"CREATE DATABASE IF NOT EXISTS {nombre_bd}") print(f"Se creó la base de datos {nombre_bd} o ya estaba creada.") except: print(f"Ocurrió un error al intentar crear la base de datos {nombre_bd}.") print("Estas son las bases de datos que tiene el servidor:") self.mostrar_bd(self)
app.py
import bd.base_datos as sqlbd #Objeto de tipo BaseDatos base_datos = sqlbd.BaseDatos(**sqlbd.acceso_bd)
En el capítulo anterior, deje la siguiente cuestión. Si te fijas, en las líneas 33 y 34, se reporta un print() y una llamada al método para mostrar las bases de datos en el servidor. Solo en caso de que salte el bloque except.
Esto mismo, se repite en las líneas 43 y 44. Entonces, te planteé el reto de intentar escribir esto una sola vez para los dos métodos o para los que vinieran.
Una forma de hacerlo, es mediante un método decorador. No te preocupes si no has conseguido hacerlo, ya que tiene bastante dificultad cuando no has utilizado apenas los decoradores.
Aquí la dificultad añadida, es que estamos dentro de una clase.
Puedes colocar el método decorador debajo del __init__:
#Decoradora para el reporte de bases de datos en el servidor def reporte_bd(funcion_parametro): def interno(self, nombre_db): funcion_parametro(self, nombre_db) print("Estas son las bases de datos que tiene el servidor:") BaseDatos.mostrar_bd(self) return interno
El nombre del método decorador es «reporte_bd». Este nombre, en el capítulo en el cual expliqué las funciones decoradoras, se presentaba como «a» en los ejemplos.
La «funcion_parametro» es la que se representaba como «b».
Y el método «interno» es el que aparecía como «c» en los ejemplos de ese capítulo.
Te cuento todo esto, por si te ayuda mejor a entender este método.
Puesto que estamos dentro de una clase, hay que pasarle el self al método interno, si no lo haces, no podrás referenciar a atributos u otros métodos de la clase.
Después, los dos métodos que quiero decorar, tienen un parámetro, «nombre_db». Lo he puesto como nombre_db, pero no es obligatorio que tenga ese mismo nombre.
Te recomiendo mejor, que pongas *args por si hay que decorar otros métodos con más parámetros:
#Decoradora para el reporte de bases de datos en el servidor def reporte_bd(funcion_parametro): def interno(self, *args): funcion_parametro(self, *args) print("Estas son las bases de datos que tiene el servidor:") BaseDatos.mostrar_bd(self) return interno
Antes de llamar a la función parámetro (línea 4), podría haber incluido algo de código. En este caso, no me hace falta, así que llamo directamente.
Finalmente, saco el print que se repetía y la llamada al método mostrar_bd() para que las muestre.
Quizás te confunda la forma de llamar al método. Esto se hace así debido al alcance. Primero tengo que hacer referencia a la clase con «BaseDatos» (con self, se hace referencia al propio objeto que se instancia, no a la clase). Usando un punto, puedo indicarle qué método quiero llamar de la clase.
Finalmente, el archivo «base_datos.py» debe quedar así. En las líneas 35 y 44 decoro los dos métodos.
import mysql.connector #conexion con la base de datos acceso_bd = {"host" : "localhost", "user" : "root", "password" : "programacionfacil", } class BaseDatos: #Conexión y cursor def __init__(self, **kwargs): self.conector = mysql.connector.connect(**kwargs) self.cursor = self.conector.cursor() #Decoradora para el reporte de bases de datos en el servidor def reporte_bd(funcion_parametro): def interno(self, nombre_db): funcion_parametro(self, nombre_db) print("Estas son las bases de datos que tiene el servidor:") BaseDatos.mostrar_bd(self) return interno #Consultas SQL def consulta(self, sql): self.cursor.execute(sql) return self.cursor #Mostrar bases de datos def mostrar_bd(self): self.cursor.execute("SHOW DATABASES") for bd in self.cursor: print(bd) #Eliminar bases de datos @reporte_bd def eliminar_bd(self, nombre_bd): try: self.cursor.execute(f"DROP DATABASE {nombre_bd}") print(f"Se eliminó la base de datos {nombre_bd} correctamente.") except: print(f"Base de datos '{nombre_bd}' no encontrada.") #Crear bases de datos @reporte_bd def crear_bd(self, nombre_bd): try: self.cursor.execute(f"CREATE DATABASE IF NOT EXISTS {nombre_bd}") print(f"Se creó la base de datos {nombre_bd} o ya estaba creada.") except: print(f"Ocurrió un error al intentar crear la base de datos {nombre_bd}.")
Dejamos el capítulo aquí. En el siguiente, te mostraré como crear un método para hacer copias de seguridad de cualquier base de datos MySQL.
No te pierdas nada de todo el contenido que tengo sobre Python.
Como se podría hacer para que el retorno de la función decoradora
cambie si la función que recibe como argumento ejecuta try o except?
Gracias por el curso!!
Empleando el bloque de código try y except dentro de la función decoradora, y retirando ese bloque dentro de la función original, para que solo quede la instrucción específica.