init
del
Herencia
Ejemplo 2 POO py
terminología POO
Terminologia POO todo en uno [Link]
Ejemplo 3 POO
La programación orientada a objetos (POO) en Python se basa en la creación de clases y
objetos. Las clases son plantillas para crear objetos, que son instancias de la clase con datos
y métodos. La sintaxis fundamental implica la definición de clases con el uso de la palabra
clave class , la definición de atributos dentro de la clase, y la definición de métodos
(funciones) que operan sobre los objetos.
1. Definición de una clase:
class NombreDeLaClase:
"""Documentación de la clase"""
# Atributos de clase (opcional)
# Métodos de la clase (funciones)
def __init__(self, *args, **kwargs):
"""Constructor de la clase (opcional)"""
# Asignar valores a los atributos de la instancia
[Link] = None # Changed 'valor' to 'None' as it was
undefined
def metodo1(self, *args, **kwargs):
"""Implementación del método 1"""
# Código del método
pass
def metodo2(self, *args, **kwargs):
"""Implementación del método 2"""
# Código del método
pass
class NombreDeLaClase: : Declara una nueva clase con el
nombre NombreDeLaClase .
ìnit(self, *args, : kwargs) **: Es el método constructor de la clase, se
ejecuta cuando se crea un nuevo objeto de la clase. self es una
referencia al objeto actual, y *args y **kwargs`permiten pasar
argumentos variables.
[Link] = valor : Define un atributo de la instancia (objeto) de la clase.
d̀ef metodo1(self, *args, : kwargs) **: Define un método (función) de la
clase. self sigue siendo una referencia al objeto actual,
y *args y **kwargs`permiten pasar argumentos variables.
2. Creación de objetos (instancias de la clase):
# Creamos un objeto de la clase "NombreDeLaClase"
objeto = NombreDeLaClase(argumento1, argumento2, ...)
objeto = NombreDeLaClase(...) : Crea una nueva instancia (objeto) de la
clase NombreDeLaClase . Los argumentos se pasan al constructor __init__() .
3. Acceso a atributos y métodos de los objetos:
# Accedemos a los atributos del objeto
valor_atributo = [Link]
# Llamamos a los métodos del objeto
resultado = objeto.metodo1(argumento1, argumento2, ...)
[Link] : Accede al valor del atributo atributo del objeto.
objeto.metodo1(...) : Llama al método metodo1 del objeto, pasando los
argumentos necesarios.
Ejemplo:
class Perro:
def __init__(self, nombre, raza):
[Link] = nombre
[Link] = raza
def ladrar(self):
print(f"{[Link]} está ladrando: Guau!")
def saludar(self):
print(f"Hola, soy {[Link]}, un {[Link]}!")
# Creamos un objeto de la clase "Perro"
mi_perro = Perro("Max", "Labrador")
# Accedemos a los atributos
print(f"El nombre del perro es: {mi_perro.nombre}")
# Llamamos a los métodos
mi_perro.ladrar()
mi_perro.saludar()
Conceptos clave de la POO en Python:
Clase: Una plantilla que define las propiedades (atributos) y métodos (comportamientos)
de los objetos que se crean a partir de ella.
Objeto: Una instancia concreta de una clase, que contiene los atributos y puede ejecutar
los métodos definidos en la clase.
Atributo: Una variable que contiene datos asociados a un objeto.
Método: Una función que define el comportamiento de un objeto.
Herencia: La capacidad de una clase (clase hija) para heredar propiedades y métodos de
otra clase (clase padre).
Encapsulamiento: La práctica de agrupar los datos y los métodos que los manipulan
dentro de un objeto, ocultando los detalles internos.
Polimorfismo: La capacidad de un objeto para tener diferentes formas o
comportamientos dependiendo del contexto.
Ventajas de la POO en Python:
Modularidad:
El código se organiza en unidades separadas (clases y objetos), lo que facilita su
mantenimiento y reutilización.
Reutilización:
Las clases y objetos pueden ser reutilizados en diferentes partes de un programa o en
diferentes programas.
Estructura:
La POO permite crear una estructura clara y organizada del código, lo que facilita la
comprensión y el desarrollo del software.
Facilidad de mantenimiento:
La modularidad y la reutilización hacen que el código sea más fácil de mantener y
actualizar.
Ejemplo 1
Transformando Script a POO: La Clase Database
La idea principal al pasar el script a POO es encapsular la lógica de interacción con la base
de datos dentro de una clase. Has llamado a esta clase Database .
El Constructor ( __init__ )
Propósito: Cuando creas una instancia (un "objeto") de una clase, necesitas que se realice
una configuración inicial. En Python, esto se hace con un método especial llamado
__init__ (conocido como constructor en otros lenguajes).
Comportamiento: Cuando llamas a la clase (ej. database = Database() ), el método
__init__ se ejecuta automáticamente.
Argumento self : La clave para que __init__ funcione es el primer argumento,
self . Python lo pasa automáticamente y representa la instancia del objeto que se está
creando. Esto te permite acceder a los atributos y métodos de esa instancia.
Configuración Inicial: En tu caso, dentro de __init__ , estableces la conexión a la base
de datos (por ejemplo, [Link] ) y creas un objeto cursor. Esto asegura que cada vez
que creas un objeto Database , ya está listo para interactuar con la base de datos.
También es el lugar ideal para verificar si la tabla existe.
Métodos de la Clase
Propósito: Los métodos son las funciones que pertenecen a una clase y operan sobre los
datos de los objetos de esa clase.
Argumento self en Métodos: Al igual que en __init__ , todos los métodos de una
clase (como view , insert , search , delete , update ) deben tener self como
su primer argumento. Esto se debe a que, cuando llamas a un método de un objeto (ej.
[Link]() ), Python pasa la instancia de ese objeto al método como el
argumento self . Si no incluyes self , Python te dará un error de que el método no
toma argumentos posicionales, pero se le dio uno (que es la instancia del objeto).
Llamadas a Métodos: En tu [Link] , en lugar de llamar a funciones del módulo
backend (ej. [Link]() ), ahora llamas a los métodos del objeto database
que has creado (ej. [Link]() ).
Ventajas de la POO (y cómo mejorar aún más)
Al principio, puede parecer que la POO es solo "poner funciones dentro de una clase". Sin
embargo, el verdadero poder radica en el diseño y la eliminación de código repetido.
Encapsulación: Agrupas la lógica de la base de datos en un solo lugar ( Database class).
Reutilización: Una vez que defines la clase, puedes crear múltiples objetos Database si
lo necesitas, cada uno con su propia conexión y estado (aunque en tu caso, con una sola
base de datos, quizás no sea tan evidente).
Mejora de Diseño: Notaste que al principio, cada método (como view , insert ) volvía
a establecer una conexión y un cursor. Esto es ineficiente y repetitivo.
La Mejora Clave: La ventaja real de la POO es que puedes establecer la conexión y el
cursor una sola vez en el método __init__ , y luego referirte a ellos (usando
[Link] y [Link] , por ejemplo) en los otros métodos. Esto
evita la repetición de código y hace que tu programa sea más eficiente y fácil de
mantener.
En resumen, has aprendido a:
1. Definir una clase ( Database ).
2. Utilizar el método especial __init__ para inicializar objetos.
3. Entender la importancia del argumento self en todos los métodos de la clase.
4. Llamar a los métodos de un objeto instanciado.
5. Reconocer cómo la POO puede llevar a un código más organizado y, crucialmente, a un
mejor diseño al reducir la repetición de tareas (como la conexión a la base de datos) al
inicio del ciclo de vida del objeto.
Mejorando el Diseño de la Clase Database
El problema inicial era que cada método de tu clase Database (como view , insert ,
search , etc.) establecía su propia conexión a la base de datos y su propio cursor, y luego
los cerraba. Esto es ineficiente y no aprovecha el poder de la POO para manejar recursos.
Centralizando la Conexión y el Cursor
La solución, que implementaste, es la siguiente:
1. Conexión en __init__ :
La conexión a la base de datos ( [Link] ) y el objeto cursor ( [Link] ) se
crean una sola vez dentro del método __init__ .
Almacenas estos recursos como atributos de la instancia (usando [Link] y
[Link] ). Esto los hace accesibles desde cualquier otro método del objeto
Database .
2. Eliminando la Repetición:
Una vez que [Link] y [Link] están definidos en __init__ , puedes
eliminar las líneas de conexión y creación de cursor de todos los demás métodos
( view , insert , search , delete , update ).
En lugar de [Link](...) o [Link]() , ahora usas
[Link](...) y [Link]() . El self. es crucial
porque indica que estás accediendo al atributo cur o conn de la instancia actual
del objeto.
Manejo de Errores y la Importancia de self
Al hacer estos cambios, encontraste errores comunes de Python relacionados con el alcance
de las variables y los atributos de clase:
NameError: name 'cur' is not defined : Esto ocurre cuando intentas usar una
variable ( cur ) que solo existía localmente dentro de __init__ o en versiones
anteriores de los métodos. La solución es referirte a ella como un atributo del objeto:
[Link] .
AttributeError: 'Database' object has no attribute 'cur' : Esto
sucede si no asignaste cur como un atributo del objeto (ej. [Link] =
[Link]() ) dentro de __init__ . Aunque lo crees, si no lo asignas a self , no
se "pega" al objeto.
El Método __del__ para Cerrar la Conexión
Problema de Cierre: Notaste que si cierras la conexión ( [Link]() ) después de
cada operación (como en el método view ), la base de datos se cierra y no puedes
realizar más operaciones sin volver a abrirla, lo que anularía el propósito del nuevo
diseño.
__del__ (El Destructor): Python proporciona otro método especial, __del__ , que se
ejecuta justo antes de que una instancia de un objeto sea destruida (generalmente
cuando el programa termina o cuando el objeto ya no es referenciado).
Uso: Es el lugar ideal para cerrar recursos que se mantuvieron abiertos durante la vida
del objeto, como la conexión a la base de datos ( [Link]() ). Esto asegura
que la conexión se cierra de forma limpia al finalizar el programa, evitando problemas de
corrupción o de que datos no se "commit" si otro programa intenta acceder a la base de
datos.
Alternativas de Commit: Aunque __del__ es bueno para cerrar, también mencionaste
la idea de un botón de "Commit" en la GUI. Esto es una excelente idea para aplicaciones
más complejas, permitiendo al usuario decidir cuándo guardar los cambios
permanentemente, y centralizando la lógica de commit en un solo método dedicado.
Conclusión y Próximos Pasos
Has logrado un diseño de clase mucho más robusto y eficiente. Al centralizar la gestión de la
conexión y el cursor, has reducido el código repetitivo y mejorado la coherencia de tu
interacción con la base de datos.
Como ejercicio, el desafío de convertir la parte frontend (Tkinter) a POO es una práctica
excelente. Te ayudará a consolidar aún más tus conocimientos al aplicar los mismos
principios de encapsulación y gestión de recursos a la interfaz de usuario.