CLASES en PYTHON, TODOS los pilares de POO aplicados a un EJEMPLO COMPLETO desde CERO

 

Clases en Python para Principiantes

¿Qué es una clase?

Imagina que una clase es como un molde o plantilla para crear objetos. Por ejemplo, si quieres hacer galletas, usas un molde. La clase sería el molde, y cada galleta sería un objeto.

Conceptos básicos

  • Clase: Molde o plantilla

  • Objeto: Instancia creada a partir de la clase

  • Atributos: Características del objeto (como variables)

  • Métodos: Acciones que puede realizar el objeto (como funciones)

Sintaxis básica

python
class NombreClase:
    # Atributos y métodos van aquí
    pass

Ejemplo práctico: Crear una clase "Perro"

python
class Perro:
    # Método especial: se ejecuta al crear un objeto
    def __init__(self, nombre, raza, edad):
        # Atributos de instancia
        self.nombre = nombre
        self.raza = raza
        self.edad = edad
    
    # Método (función dentro de la clase)
    def ladrar(self):
        return f"{self.nombre} dice: ¡Guau!"
    
    def describir(self):
        return f"{self.nombre} es un {self.raza} de {self.edad} años"

Crear objetos (instancias)

python
# Crear objetos a partir de la clase Perro
perro1 = Perro("Max", "Labrador", 3)
perro2 = Perro("Luna", "Pastor Alemán", 2)

# Usar los métodos
print(perro1.ladrar())      # Max dice: ¡Guau!
print(perro2.describir())   # Luna es un Pastor Alemán de 2 años

# Acceder a los atributos
print(perro1.nombre)        # Max
print(perro2.edad)          # 2

¿Qué es self?

  • self se refiere a la instancia actual del objeto

  • Es como decir "yo mismo" o "este objeto"

  • Siempre es el primer parámetro de los métodos

Método __init__

  • Es el constructor de la clase

  • Se ejecuta automáticamente cuando creas un nuevo objeto

  • Se usa para inicializar los atributos

Ejemplo más completo: Cuenta Bancaria

python
class CuentaBancaria:
    def __init__(self, titular, saldo_inicial=0):
        self.titular = titular
        self.saldo = saldo_inicial
    
    def depositar(self, cantidad):
        self.saldo += cantidad
        return f"Depósito exitoso. Saldo actual: ${self.saldo}"
    
    def retirar(self, cantidad):
        if cantidad <= self.saldo:
            self.saldo -= cantidad
            return f"Retiro exitoso. Saldo actual: ${self.saldo}"
        else:
            return "Fondos insuficientes"
    
    def consultar_saldo(self):
        return f"Saldo de {self.titular}: ${self.saldo}"

# Usar la clase
cuenta1 = CuentaBancaria("Ana", 1000)
cuenta2 = CuentaBancaria("Carlos", 500)

print(cuenta1.consultar_saldo())  # Saldo de Ana: $1000
print(cuenta1.depositar(200))     # Depósito exitoso. Saldo actual: $1200
print(cuenta1.retirar(300))       # Retiro exitoso. Saldo actual: $900

Ventajas de usar clases

  1. Organización: Código más ordenado y fácil de entender

  2. Reutilización: Puedes crear muchos objetos de la misma clase

  3. Modularidad: Fácil de modificar y mantener

  4. Abstracción: Ocultas la complejidad interna

Resumen visual

text
CLASE Perro (molde)
    │
    ├── Atributos: nombre, raza, edad
    │
    └── Métodos: ladrar(), describir()
            │
            ↓
OBJETOS (galletas del molde)
    │
    ├── perro1: nombre="Max", raza="Labrador", edad=3
    │
    └── perro2: nombre="Luna", raza="Pastor Alemán", edad=2

Consejos para principiantes

  1. Empieza simple: Crea clases básicas primero

  2. Nombres descriptivos: Usa nombres que expliquen qué hace la clase

  3. Practica: Crea clases para cosas de la vida real (coche, libro, persona)

  4. No te rindas: Al principio puede ser confuso, pero con práctica se entiende


Tutorial de Clases en Python: Ejemplo Original de Personajes RPG

Voy a crear un tutorial completo basado en ese contenido, con un ejemplo práctico de un sistema de personajes RPG.

1. Abstracción - Creando nuestra Clase Base

python
# Clase Personaje (nuestra plantilla/matriz)
class Personaje:
    def __init__(self, nombre, fuerza, inteligencia, defensa, vida):
        # Atributos de instancia
        self.nombre = nombre
        self.fuerza = fuerza
        self.inteligencia = inteligencia
        self.defensa = defensa
        self.vida = vida
        self.vida_maxima = vida  # Para poder curarse luego
        self.aguante = fuerza * vida  # Atributo derivado
        self.turno = False  # Atributo independiente
    
    def atributos(self):
        """Muestra los atributos del personaje"""
        print(f"{self.nombre}:")
        print(f"• Fuerza: {self.fuerza}")
        print(f"• Inteligencia: {self.inteligencia}")
        print(f"• Defensa: {self.defensa}")
        print(f"• Vida: {self.vida}")
        print(f"• Aguante: {self.aguante}")
    
    def subir_nivel(self, fuerza=0, inteligencia=0, defensa=0):
        """Mejora las estadísticas del personaje"""
        self.fuerza += fuerza
        self.inteligencia += inteligencia
        self.defensa += defensa
        self.aguante = self.fuerza * self.vida  # Recalculamos aguante
    
    def esta_vivo(self):
        """Verifica si el personaje está vivo"""
        return self.vida > 0
    
    def morir(self):
        """Marca al personaje como muerto"""
        self.vida = 0
        print(f"💀 {self.nombre} ha muerto")
    
    def daño(self, enemigo):
        """Calcula el daño que haría a un enemigo"""
        return self.fuerza - enemigo.defensa
    
    def atacar(self, enemigo):
        """Realiza un ataque a otro personaje"""
        daño = self.daño(enemigo)
        enemigo.vida -= daño
        
        print(f"⚔️ {self.nombre} ataca a {enemigo.nombre}")
        print(f"💥 Causa {daño} puntos de daño")
        
        if enemigo.esta_vivo():
            print(f"❤️ {enemigo.nombre} tiene {enemigo.vida} puntos de vida")
        else:
            enemigo.morir()
    
    def curar(self, puntos_curacion=10):
        """Cura al personaje"""
        if self.esta_vivo():
            self.vida = min(self.vida + puntos_curacion, self.vida_maxima)
            print(f"✨ {self.nombre} se cura {puntos_curacion} puntos")
            print(f"❤️ Vida actual: {self.vida}/{self.vida_maxima}")
        else:
            print(f"❌ {self.nombre} está muerto, no se puede curar")

2. Probando nuestra Clase Base

python
# Creando personajes
heroe = Personaje("Aragorn", fuerza=15, inteligencia=10, defensa=8, vida=100)
villano = Personaje("Sauron", fuerza=18, inteligencia=12, defensa=6, vida=80)

# Mostrando atributos
print("=== ATRIBUTOS INICIALES ===")
heroe.atributos()
print()
villano.atributos()

# Probando métodos
print("\n=== SUBIENDO DE NIVEL ===")
heroe.subir_nivel(fuerza=2, inteligencia=1, defensa=1)
heroe.atributos()

print("\n=== COMBATE ===")
heroe.atacar(villano)
villano.atacar(heroe)

print("\n=== CURACIÓN ===")
heroe.curar(15)

3. Herencia - Creando Clases Especializadas

python
class Guerrero(Personaje):
    def __init__(self, nombre, fuerza, inteligencia, defensa, vida, espada):
        # Llamamos al constructor de la clase padre
        super().__init__(nombre, fuerza, inteligencia, defensa, vida)
        self.espada = espada  # Daño adicional de la espada
    
    def cambiar_arma(self):
        """Permite cambiar el arma del guerrero"""
        print("\n🗡️ Selecciona un arma:")
        print("1. Espada de acero - Daño: 8")
        print("2. Hacha de guerra - Daño: 12")
        print("3. Martillo de thor - Daño: 15")
        
        try:
            opcion = int(input("Elige (1-3): "))
            if opcion == 1:
                self.espada = 8
            elif opcion == 2:
                self.espada = 12
            elif opcion == 3:
                self.espada = 15
            else:
                print("❌ Opción inválida, manteniendo arma actual")
        except:
            print("❌ Error al seleccionar arma")
    
    def atributos(self):
        """Sobreescribe el método para mostrar también el arma"""
        super().atributos()
        print(f"• Daño de espada: {self.espada}")
    
    def daño(self, enemigo):
        """Sobreescribe el cálculo de daño"""
        return (self.fuerza * self.espada) - enemigo.defensa

class Mago(Personaje):
    def __init__(self, nombre, fuerza, inteligencia, defensa, vida, libro):
        super().__init__(nombre, fuerza, inteligencia, defensa, vida)
        self.libro = libro  # Multiplicador de hechizos
    
    def atributos(self):
        """Sobreescribe el método para mostrar también el libro"""
        super().atributos()
        print(f"• Poder del libro: {self.libro}")
    
    def daño(self, enemigo):
        """Sobreescribe el cálculo de daño usando inteligencia"""
        return (self.inteligencia * self.libro) - enemigo.defensa
    
    def lanzar_hechizo(self, enemigo):
        """Método exclusivo del mago"""
        if self.inteligencia > 10:
            daño_extra = self.inteligencia * 2
            enemigo.vida -= daño_extra
            print(f"🔮 {self.nombre} lanza un hechizo poderoso!")
            print(f"✨ Causa {daño_extra} puntos de daño mágico")
        else:
            print(f"❌ {self.nombre} no tiene suficiente inteligencia para lanzar hechizos")

4. Probando la Herencia

python
# Creando personajes especializados
guerrero = Guerrero("Guts", fuerza=20, inteligencia=5, defensa=10, vida=120, espada=8)
mago = Mago("Gandalf", fuerza=8, inteligencia=18, defensa=6, vida=90, libro=3)

print("=== GUERRERO ===")
guerrero.atributos()

print("\n=== MAGO ===")
mago.atributos()

print("\n=== COMBATE ESPECIALIZADO ===")
guerrero.atacar(mago)
mago.atacar(guerrero)

# Probando métodos exclusivos
print("\n=== HECHIZO MAGICO ===")
mago.lanzar_hechizo(guerrero)

print("\n=== CAMBIANDO ARMA ===")
guerrero.cambiar_arma()
guerrero.atributos()

5. Polimorfismo - Sistema de Combate

python
def combate(jugador1, jugador2):
    """Función que puede recibir cualquier tipo de personaje"""
    print(f"🎯 COMIENZA EL COMBATE: {jugador1.nombre} vs {jugador2.nombre}")
    print("=" * 50)
    
    turno = 0
    while jugador1.esta_vivo() and jugador2.esta_vivo():
        turno += 1
        print(f"\n--- TURNO {turno} ---")
        
        # Jugador 1 ataca a Jugador 2
        if jugador1.esta_vivo():
            jugador1.atacar(jugador2)
        
        # Jugador 2 ataca a Jugador 1
        if jugador2.esta_vivo():
            jugador2.atacar(jugador1)
    
    # Determinar ganador
    print("\n" + "=" * 50)
    if jugador1.esta_vivo():
        print(f"🏆 {jugador1.nombre} GANA EL COMBATE!")
    elif jugador2.esta_vivo():
        print(f"🏆 {jugador2.nombre} GANA EL COMBATE!")
    else:
        print("💀 EMPATE - Ambos combatientes han muerto")

def que_soy(personaje):
    """Ejemplo de polimorfismo"""
    print(f"Soy un {type(personaje).__name__} llamado {personaje.nombre}")

# Probando el sistema de combate
print("=== SISTEMA DE COMBATE ===")
arquero = Personaje("Legolas", fuerza=12, inteligencia=14, defensa=7, vida=95)
paladin = Guerrero("Uther", fuerza=16, inteligencia=12, defensa=12, vida=110, espada=10)

combate(arquero, paladin)

print("\n=== POLIMORFISMO ===")
personajes = [heroe, guerrero, mago, arquero, paladin]
for p in personajes:
    que_soy(p)

6. Encapsulación (Opcional - Para Entender el Concepto)

python
class PersonajeProtegido:
    def __init__(self, nombre, fuerza):
        self.__nombre = nombre  # Atributo "privado"
        self.__fuerza = fuerza
    
    # Getters
    def get_nombre(self):
        return self.__nombre
    
    def get_fuerza(self):
        return self.__fuerza
    
    # Setters con validación
    def set_fuerza(self, nueva_fuerza):
        if nueva_fuerza < 0:
            print("❌ La fuerza no puede ser negativa")
        else:
            self.__fuerza = nueva_fuerza
            print(f"✅ Fuerza cambiada a: {nueva_fuerza}")

# Probando encapsulación
pj_protegido = PersonajeProtegido("Protector", 10)
print(f"Nombre: {pj_protegido.get_nombre()}")
pj_protegido.set_fuerza(-5)  # Esto mostrará error
pj_protegido.set_fuerza(15)  # Esto funcionará

7. Ejemplo Completo: Arena de Combate

python
class Arena:
    def __init__(self, nombre):
        self.nombre = nombre
        self.combatientes = []
    
    def agregar_combatiente(self, personaje):
        self.combatientes.append(personaje)
        print(f"✅ {personaje.nombre} se une a la arena {self.nombre}")
    
    def torneo(self):
        print(f"\n🏟️ COMIENZA EL TORNEO EN {self.nombre}")
        print("=" * 60)
        
        for i in range(len(self.combatientes)):
            for j in range(i + 1, len(self.combatientes)):
                # Restauramos la vida para el torneo
                self.combatientes[i].vida = self.combatientes[i].vida_maxima
                self.combatientes[j].vida = self.combatientes[j].vida_maxima
                
                print(f"\n🎯 ENFRENTAMIENTO: {self.combatientes[i].nombre} vs {self.combatientes[j].nombre}")
                combate(self.combatientes[i], self.combatientes[j])

# Creando una arena y organizando un torneo
arena_epica = Arena("Coliseo del Dragón")

# Agregando combatientes
arena_epica.agregar_combatiente(guerrero)
arena_epica.agregar_combatiente(mago)
arena_epica.agregar_combatiente(arquero)
arena_epica.agregar_combatiente(paladin)

# Iniciando torneo
arena_epica.torneo()

Resumen de Conceptos Aprendidos:

  1. Abstracción: Creamos la clase Personaje como molde

  2. Encapsulación: Protegemos atributos con getters/setters

  3. HerenciaGuerrero y Mago heredan de Personaje

  4. Polimorfismo: Mismo método atacar() se comporta diferente según la clase

Ejercicios para Practicar:

  1. Crea una clase Arquero que herede de Personaje

  2. Implementa un sistema de experiencia y niveles

  3. Crea un método usar_pocion() que cure al personaje

  4. Implementa ataques especiales para cada clase

Comentarios

Entradas populares de este blog

1-Teclas

2-canvas

3-1-Personajes