← Python EspañolChapter 10 of 13

Programación Orientada a Objetos

## Objetivos de Aprendizaje - Entender clases y objetos - Dominar herencia y polimorfismo - Aprender encapsulamiento y ocultación de datos - Trabajar con métodos especiales ## Clases y Objetos ### Definir una Clase ```python class Perro: """Una clase de perro simple.""" def __init__(self, nombre, edad): self.nombre = nombre # Atributo de instancia self.edad = edad def ladrar(self): return f"¡{self.nombre} dice Guau!" def obtener_info(self): return f"{self.nombre} tiene {self.edad} años" # Creando una instancia mi_perro = Perro("Buddy", 3) print(mi_perro.ladrar()) # ¡Buddy dice Guau! print(mi_perro.obtener_info()) # Buddy tiene 3 años ``` ### El Método __init__ ```python class Perro: def __init__(self, nombre, edad=1): self.nombre = nombre self.edad = edad ``` ### Atributos de Instancia ```python perro1 = Perro("Rex", 2) perro2 = Perro("Max") print(perro1.nombre) # Rex print(perro2.edad) # 1 (por defecto) ``` ## Atributos de Clase ```python class Perro: especie = "Canis familiaris" # Atributo de clase def __init__(self, nombre, edad): self.nombre = nombre # Atributo de instancia self.edad = edad print(Perro.especie) # Canis familiaris print(perro1.especie) # Canis familiaris ``` ## Métodos de Instancia vs de Clase ### Métodos de Instancia ```python class Perro: def __init__(self, nombre): self.nombre = nombre def ladrar(self): # Método de instancia - toma self return f"{self.nombre} ladra!" ``` ### Métodos de Clase ```python class Perro: especie = "Canis" @classmethod def obtener_especie(cls): return cls.especie print(Perro.obtener_especie()) # Canis ``` ### Métodos Estáticos ```python class Matematica: @staticmethod def sumar(a, b): return a + b print(Matematica.sumar(2, 3)) # 5 ``` ## Herencia ### Herencia Básica ```python class Animal: def __init__(self, nombre): self.nombre = nombre def hablar(self): raise NotImplementedError class Perro(Animal): # Hereda de Animal def hablar(self): return f"{self.nombre} dice ¡Guau!" class Gato(Animal): def hablar(self): return f"{self.nombre} dice ¡Miau!" perro = Perro("Buddy") gato = Gato("Whiskers") print(perro.hablar()) # Buddy dice ¡Guau! print(gato.hablar()) # Whiskers dice ¡Miau! ``` ### La Función super() ```python class Animal: def __init__(self, nombre): self.nombre = nombre class Perro(Animal): def __init__(self, nombre, raza): super().__init__(nombre) # Llama al __init__ del padre self.raza = raza perro = Perro("Rex", "Golden Retriever") print(perro.nombre) # Rex print(perro.raza) # Golden Retriever ``` ### Herencia Múltiple ```python class Volador: def volar(self): return "¡Volando!" class Nadador: def nadar(self): return "¡Nadando!" class Pato(Volador, Nadador): pass pato = Pato() print(pato.volar()) # ¡Volando! print(pato.nadar()) # ¡Nadando! ``` ## Polimorfismo ```python def hacer_hablar(animal): print(animal.hablar()) animales = [Perro("Rex"), Gato("Whiskers")] for animal in animales: hacer_hablar(animal) # Rex dice ¡Guau! # Whiskers dice ¡Miau! ``` ## Encapsulamiento ### Atributos Privados ```python class CuentaBancaria: def __init__(self, saldo): self._saldo = saldo # Convención: privado def obtener_saldo(self): return self._saldo def depositar(self, cantidad): if cantidad > 0: self._saldo += cantidad return True return False cuenta = CuentaBancaria(100) print(cuenta.obtener_saldo()) # 100 # cuenta._saldo # Todavía accesible pero no recomendado ``` ### Name Mangling ```python class MiClase: def __init__(self): self.__privado = 42 # Se transforma a _MiClase__privado obj = MiClase() print(obj._MiClase__privado) # 42 (no hagas esto) ``` ### Decorador Property ```python class CuentaBancaria: def __init__(self, saldo): self._saldo = saldo @property def saldo(self): return self._saldo @saldo.setter def saldo(self, valor): if valor >= 0: self._saldo = valor else: raise ValueError("El saldo no puede ser negativo") cuenta = CuentaBancaria(100) print(cuenta.saldo) # 100 cuenta.saldo = 200 # Usa el setter ``` ## Métodos Especiales (Magic Methods) ### __str__ y __repr__ ```python class Persona: def __init__(self, nombre, edad): self.nombre = nombre self.edad = edad def __str__(self): return f"{self.nombre}, {self.edad}" def __repr__(self): return f"Persona('{self.nombre}', {self.edad})" p = Persona("Ana", 30) print(str(p)) # Ana, 30 print(repr(p)) # Persona('Ana', 30) ``` ### __eq__ y __hash__ ```python class Punto: def __init__(self, x, y): self.x = x self.y = y def __eq__(self, otro): return self.x == otro.x and self.y == otro.y def __hash__(self): return hash((self.x, self.y)) p1 = Punto(1, 2) p2 = Punto(1, 2) print(p1 == p2) # True print(hash(p1) == hash(p2)) # True (puede usar en sets/dicts) ``` ### __len__ y __getitem__ ```python class Inventario: def __init__(self): self.elementos = [] def agregar(self, elemento): self.elementos.append(elemento) def __len__(self): return len(self.elementos) def __getitem__(self, indice): return self.elementos[indice] inv = Inventario() inv.agregar("manzana") inv.agregar("plátano") print(len(inv)) # 2 print(inv[0]) # manzana ``` ### __call__ ```python class Multiplicador: def __init__(self, factor): self.factor = factor def __call__(self, x): return x * self.factor doblar = Multiplicador(2) print(doblar(5)) # 10 (se llama como función) ``` ## Clases Abstractas ```python from abc import ABC, abstractmethod class Forma(ABC): @abstractmethod def area(self): pass @abstractmethod def perimetro(self): pass class Rectangulo(Forma): def __init__(self, ancho, alto): self.ancho = ancho self.alto = alto def area(self): return self.ancho * self.alto def perimetro(self): return 2 * (self.ancho + self.alto) # forma = Forma() # TypeError: No se puede instanciar clase abstracta rect = Rectangulo(5, 3) print(rect.area()) # 15 ``` ## Data Classes (Python 3.7+) ```python from dataclasses import dataclass @dataclass class Persona: nombre: str edad: int email: str = "desconocido@ejemplo.com" # Por defecto persona = Persona("Ana", 30) print(persona) # Persona(nombre='Ana', edad=30, email='desconocido@ejemplo.com') ``` ## Resumen - Las clases definen objetos con atributos y métodos - `__init__` inicializa nuevas instancias - Los atributos de instancia pertenecen a objetos; los de clase a la clase - `@classmethod` y `@staticmethod` para tipos alternativos de métodos - Herencia: `class Hijo(Padre):` - `super().__init__()` llama al constructor padre - Usa la convención `_attr` para atributos privados - `@property` crea atributos administrados - Métodos especiales: `__str__`, `__eq__`, `__init__`, etc. - `@dataclass` auto-genera código repetitivo

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →