Apariencia
📙 Clase 13 — Clases y objetos
Fase 3 · Programación Orientada a Objetos ⬅️ Volver al índice de clases
🎯 Qué aprendí
- Qué es una clase (el molde) y un objeto (lo fabricado con el molde).
__init__(el constructor) yself(la referencia a "yo mismo").- Por qué la POO es el salto para tus apps: datos + comportamiento juntos.
📖 PARTE TEÓRICA
🏭 1. Clase = molde, objeto = instancia
Hasta ahora modelas un contacto como un diccionario suelto y sus acciones como funciones sueltas. La POO junta datos + comportamiento en una sola pieza: la clase.
python
class Contacto: # la CLASE: el molde
def __init__(self, nombre, tel): # el CONSTRUCTOR: cómo se fabrica uno
self.nombre = nombre # atributo: dato que vive EN el objeto
self.tel = tel
def descripcion(self): # método: función que vive EN el objeto
return f"{self.nombre} ({self.tel})"
# Crear OBJETOS (instancias): llamar a la clase como si fuera función
c1 = Contacto("Ana", "999-111")
c2 = Contacto("Luis", "988-222")
print(c1.descripcion()) # Ana (999-111)
print(c2.descripcion()) # Luis (988-222) ← cada objeto tiene SUS datos
print(type(c1).__name__) # Contacto CLASE (molde) objetos (instancias)
┌───────────────────┐ c1 ▶ nombre="Ana", tel="999-111"
│ class Contacto: │ ────▶ c2 ▶ nombre="Luis", tel="988-222"
│ __init__ │ (mismas "piezas", valores propios)
│ descripcion() │
└───────────────────┘💡 Ya usas objetos hace semanas sin saberlo:
ctk.CTkButton(...)es crear una instancia de la claseCTkButton. Cada botón es un objeto con sus propios datos (text,command…).
🐣 2. __init__: el constructor
__init__ corre automáticamente al crear el objeto. Es donde recibes los datos iniciales y los guardas como atributos.
python
class Contacto:
def __init__(self, nombre, tel):
# └── los argumentos de Contacto("Ana", "999-111")
self.nombre = nombre # "guárdalo en MÍ"
self.tel = tel📌 Se llama dunder init (double underscore). No lo llamas tú: lo llama Python al hacer
Contacto(...).
🪞 3. self: "yo mismo"
self es la referencia al objeto concreto sobre el que se está trabajando. Es el primer parámetro de todo método, y Python lo pasa solo:
python
c1.descripcion()
# Python lo traduce a: Contacto.descripcion(c1)
# └── ese es selfPor eso dentro del método, self.nombre significa "el nombre de este contacto" — c1 da "Ana" y c2 da "Luis" con el mismo código.
🧪 Tip de entrevista: "¿Qué es
self?" → La referencia a la instancia actual. Permite que un método lea/modifique los atributos de ese objeto. Siempre es el primer parámetro (el nombreselfes convención, no palabra reservada).
✏️ 4. Los atributos se leen y modifican con punto
python
print(c1.nombre) # Ana (leer)
c1.tel = "111-000" # (modificar)
print(c1.descripcion()) # Ana (111-000)⚠️ Olvidar
self.dentro de un método (nombre = nombreen vez deself.nombre = nombre) crea una variable local que muere al salir — el objeto queda sin el dato. Error clásico de principiante en POO.
🖥️ EN TU APP DE ESCRITORIO
La POO reemplaza a los diccionarios sueltos como modelo de datos de tu app:
python
class Tarea:
def __init__(self, texto):
self.texto = texto
self.hecha = False
def completar(self):
self.hecha = True
def etiqueta(self):
"""El texto listo para mostrar en la GUI."""
return f"✅ {self.texto}" if self.hecha else f"⬜ {self.texto}"
tareas = [Tarea("Comprar pan"), Tarea("Estudiar Python")]
tareas[1].completar()
for t in tareas:
print(t.etiqueta())
# ⬜ Comprar pan
# ✅ Estudiar PythonCompara con el dict de la Clase 04:
dict {"texto": ..., "hecha": ...} | clase Tarea | |
|---|---|---|
| Datos | ✅ | ✅ |
Comportamiento (completar, etiqueta) | ❌ funciones sueltas | ✅ vive junto a los datos |
| Errores de tipeo | t["hehca"] crea clave nueva 💥 | t.hehca → AttributeError claro |
| Autocompletado del editor | pobre | completo |
💡 El dict sigue siendo perfecto para mover datos (formulario → BD). La clase gana cuando el dato tiene comportamiento. Ambos conviven:
Tareapuede tener un método que se convierta a dict para guardarse.
🗄️ CON BASE DE DATOS (caso de uso)
El puente dict = fila (Clase 04) se extiende: objeto ↔ dict ↔ fila.
python
class Contacto:
def __init__(self, nombre, tel):
self.nombre = nombre
self.tel = tel
def a_dict(self):
"""Para INSERT con parámetros :nombre / :tel"""
return {"nombre": self.nombre, "tel": self.tel}
c = Contacto("Ana", "999-111")
con.execute("INSERT INTO contactos VALUES (:nombre, :tel)", c.a_dict())🗄️ Los ORMs profesionales (SQLAlchemy) hacen exactamente esto en grande: una clase por tabla, un objeto por fila. Ya estás entendiendo su fundamento.
🏋️ EJERCICIOS CON SOLUCIÓN
Ejercicio 1 — Tu primera clase
Crea la clase Producto con nombre y precio, y un método mostrar() que devuelva "Teclado: S/120". Crea dos productos y muéstralos.
Ver solución
python
class Producto:
def __init__(self, nombre, precio):
self.nombre = nombre
self.precio = precio
def mostrar(self):
return f"{self.nombre}: S/{self.precio}"
p1 = Producto("Teclado", 120)
p2 = Producto("Mouse", 45)
print(p1.mostrar()) # Teclado: S/120
print(p2.mostrar()) # Mouse: S/45Ejercicio 2 — Comportamiento
Agrega a Producto un método aplicar_descuento(porcentaje) que modifique su precio.
Ver solución
python
class Producto:
def __init__(self, nombre, precio):
self.nombre = nombre
self.precio = precio
def aplicar_descuento(self, porcentaje):
self.precio = self.precio * (1 - porcentaje / 100)
p = Producto("Teclado", 120)
p.aplicar_descuento(25)
print(p.precio) # 90.0Ejercicio 3 — Encuentra el bug
python
class Usuario:
def __init__(self, nombre):
nombre = nombre
u = Usuario("Ana")
print(u.nombre)Ver solución
python
# AttributeError: 'Usuario' object has no attribute 'nombre'
# Falta self.: 'nombre = nombre' asigna a una variable LOCAL que muere al salir.
# Correcto:
class Usuario:
def __init__(self, nombre):
self.nombre = nombre❓ Preguntas y respuestas (autoevaluación)
1. ¿Qué diferencia hay entre clase y objeto?
La clase es el molde (definición); el objeto es una instancia creada con ese molde, con sus propios valores.
2. ¿Cuándo se ejecuta __init__?
Automáticamente al crear la instancia:
Contacto("Ana", "999").
3. ¿Qué es self y quién lo pasa?
La referencia a la instancia actual; lo pasa Python solo al llamar
objeto.metodo().
4. ¿Qué error da t.hehca (typo) en una clase vs t["hehca"] en un dict?
La clase lanza
AttributeErroral leer (falla claro y rápido); en el dict, si asignast["hehca"]=Truecrea silenciosamente una clave nueva y el bug se esconde.
📎 Apuntes relacionados
- El modelo con dicts que esto mejora → Clase 04
- Los objetos CTk que ya usas → CustomTkinter
➡️ Siguiente
Clase 14 · Métodos y atributos — atributos de clase vs de instancia.