Programación Orientada a Objetos
Autor
waldo hidalgo
Fecha de publicación

Bienvenidos a esta primera publicación en mi nuevo blog. Esta publicación pertenecerá a una serie de publicaciones categorizadas como tutorial de python las cuales se encontrarán incluidas en la categoría padre llamada tutoriales. Sin más preambulo, el tópico principal de esta publicación serán las clases, definir qué son, para qué se utilizan, cómo se utilizan, conceptos relacionados y una serie de ejercicios al finalizar cada explicación de conceptos relacionados.
Las clases son una forma de agrupar datos y funcionalidades en una sola entidad desde la cual es posible crear un nuevo tipo de objeto a partir de la creación de instancias de dicho tipo. En Python, las clases se definen utilizando la palabra clave class. Dentro de la clase se definen los atributos(datos) y métodos(funcionalidad) que cada instancia de la clase tendrá. Los atributos son variables que se crean dentro de la clase y pueden ser accedidas por los métodos de la clase. Los métodos son funciones que se definen dentro de la clase y que pueden acceder y modificar los atributos de la clase.
La ventaja principal de utilizar clases es que permiten organizar el código de una forma más clara y estructurada, lo que facilita la comprensión y el mantenimiento del código. Además, permiten crear objetos que tengan comportamientos y atributos similares, lo que facilita la reutilización del código.
En esta sección, vamos a ver cómo se definen las clases en Python, cómo se crean objetos a partir de las clases, y cómo se pueden utilizar los métodos y atributos de las clases para crear objetos que tengan comportamientos y atributos específicos. Los conceptos fundamentales de esta sección son: Clases, Objetos, Atributos, Métodos, Palabra Clave Self y el método constructor __init__.
Para crear una clase se utiliza la palabra clave class
, seguida del nombre de la clase con la primera letra en mayúscula (por convención). Dentro de la clase, se puede definir un constructor usando el método especial __init__
, que se ejecuta automáticamente cuando se crea un nuevo objeto.
A continuación, se muestra la estructura fundamental para crear una clase:
1class NombreDeLaClase:2 atributo_de_clase=value13 def __init__(self, parametro1, parametro2):4 self.atributo1 = parametro15 self.atributo2 = parametro267 def metodo(self):8 pass
Donde:
self
: Hace referencia al propio objeto. Se usa para acceder a los atributos y métodos del objeto dentro de la clase.__init__
: Es un método especial llamado constructor. Se ejecuta automáticamente y de modo ímplicito al crear una instancia (objeto) de la clase.- atributo1, atributo2: Son variables asociadas a cada objeto creado.
- atributo_de_clase: Es una atributo compartido por cada instancia de la clase
Para crear una instancia de una clase, es decir, un objeto que utiliza la clase como plantilla es necesario utilizar el nombre de la clase seguido de valores para cada parámetro del método constructor __init__
. Para la estructura anterior, el código de creación de un objeto es el siguiente:
1objeto = NombreDeLaClase(argumento1,argumento2)
Ejemplo: Creacion de Clase e instanciación de objeto
El siguiente código muestra la creación de la clase Persona en la cual cada instancia de la clase debe tener dos atributos: nombre y edad. Además, se crea el método saludar que tiene como acción mostrar en consola un mensaje:
1class Persona:2 def __init__(self, nombre, edad):3 self.nombre = nombre4 self.edad = edad56 def saludar(self):7 print(f"Hola, me llamo {self.nombre} y tengo {self.edad} años.")
Lo siguiente muestra como crear objetos con valores especificos para cada parámetro:
1persona1 = Persona("Ana", 28)2persona2 = Persona("Luis", 35)34persona1.saludar()5persona2.saludar()
El encapsulamiento es uno de los principios fundamentales de la Programación Orientada a Objetos. Su propósito es ocultar los detalles internos de una clase y proteger los datos para que no sean modificados directamente desde fuera de la clase. El encapsulamiento permite:
- Controlar el acceso a los atributos.
- Evita que los objetos queden en un estado inconsistente al controlar la lógica de manipulación
Python no tiene modificadores de acceso estrictos como otros lenguajes (por ejemplo, private, protected, public en Java), pero usa convenciones de nombre para simular esos niveles:
Notación | Tipo de acceso | Uso típico |
---|---|---|
variable | público | Puede accederse desde fuera de la clase |
_variable | Protegido | Solo debe usarse dentro de la clase o subclases (convención, no obligatorio) |
__variable | Privado | No puede accederse directamente desde fuera de la clase |
A continuación, se muestra un ejemplo de acceso público al atributo saldo permitiendo su modificación sin control:
1class Cuenta:2 def __init__(self, saldo):3 self.saldo = saldo45cuenta1 = Cuenta(1000)6cuenta1.saldo = -5000
El siguiente ejemplo hace uso de la encapsulación para controlar la manipulación de atributos:
1class Cuenta:2 def __init__(self, saldo_inicial):3 self.__saldo = saldo_inicial # atributo privado45 def depositar(self, monto):6 if monto > 0:7 self.__saldo += monto89 def retirar(self, monto):10 if 0 < monto <= self.__saldo:11 self.__saldo -= monto12 else:13 print("Fondos insuficientes o monto inválido.")1415 def obtener_saldo(self):16 return self.__saldo1718cuenta = Cuenta(1000)19cuenta.depositar(500)20cuenta.retirar(200)21print(cuenta.obtener_saldo())
El print
del código anterior muestra 1300. Si se intenta acceder al atributo privado __saldo
, se muestra un error de tipo AttributeError
:
1print(cuenta.__saldo) # AttributeError: 'Cuenta' object has no attribute'__saldo'2
La herencia permite crear una clase nueva (subclase o clase hija) que hereda los atributos y métodos de otra clase (superclase o clase padre), y opcionalmente puede extenderlos o modificarlos. Permitiendo realizar:
- Reutilización de código.
- Organización jerárquica.
- Flexibilidad para personalizar comportamientos.
La sintaxis básica de herencia es la siguiente:
1class ClasePadre:2 # atributos y métodos de la clase padre3 pass45class ClaseHija(ClasePadre):6 # hereda todo de ClasePadre7 # puede agregar o sobreescribir cosas8 pass
En la herencia, el método super()
permite llamar a métodos de la clase padre desde una subclase, sin tener que escribir directamente el nombre de la clase base. Es utilizado para inicialiar atributos base o extender métodos. El siguiente ejemplo muestra el uso del método super
:
1class Empleado:2 def __init__(self, nombre, sueldo):3 self.nombre = nombre4 self.sueldo = sueldo56 def informacion(self):7 return f"Empleado: {self.nombre} - Sueldo: {self.sueldo}"89class Gerente(Empleado):10 def __init__(self, nombre, sueldo, departamento):11 super().__init__(nombre, sueldo)12 self.departamento = departamento1314 def informacion(self):15 return f"Gerente: {self.nombre} - Sueldo: {self.sueldo} - Departamento: {self.departamento}"16
El Gerente hereda de la clase empleado los atributos nombre
y sueldo
y sobreescribe el método informacion
.
Polimorfismo (del griego "muchas formas") permite que múltiples clases diferentes respondan a los mismos métodos, aunque cada una lo haga a su manera. A continuación se definen multiples clases que implementan un método llamado descripcion
pero difieren en su implementación:
1class Animal:2 def descripcion(self):3 return "Este es un animal."45class Perro(Animal):6 def descripcion(self):7 return "Este es un perro."89class Gato(Animal):10 def descripcion(self):11 return "Este es un gato."
Las actividades propuestas se encuentra en el siguiente repositorio de github: Link . Las referencias que se mencionen serán con respecto a dicho repositorio.
En la carpeta ejercicios\encapsulamiento
en esta misma ruta, se encuentra el archivo llamado encapsulamiento en el cual deberás crear una clase Producto que tenga un atributo privado __precio
. Implementa métodos para:
- Establecer el precio (debe ser llamado set_precio), solo si es mayor que cero.
- Obtener el precio (debe ser llamado get_precio).
Ejemplo de implementación esperada:
1p = Producto()2p.set_precio(1500)3print(p.get_precio()) # Debe mostrar 150045p.set_precio(-200) # No debe modificar el precio
Una vez hayas creado la clase y sus métodos, deberás ejecutar los test unitarios para validar correctamente la implementación. En la consola de comandos deberás ejecutar el siguiente comando posicionado en dicha ruta:
1py test_encapsulamiento.py encapsulamiento
Una vez hayas realizado la actividad puedes visualizar una posible solución en el archivo ubicado en esta ruta: 1_programacion_orientada_a_objetos/soluciones/encapsulamiento/solucion.py
.
En la carpeta ejercicios\herencia
en esta misma ruta, se encuentra el archivo llamado herencia en el cual deberás crear una clase base Figura con un método area() (que debe retornar 0 por defecto). Luego, crea dos clases que hereden de ella:
- Clase Rectangulo, con atributos ancho y alto.
- Clase Circulo, con atributo radio.
Ambas deben sobrescribir el método area() para devolver el área correspondiente.
Una vez hayas creado la clase y sus métodos, deberás ejecutar los test unitarios para validar correctamente la implementación. En la consola de comandos deberás ejecutar el siguiente comando posicionado en dicha ruta:
1py test_herencia.py herencia
Una vez hayas realizado la actividad puedes visualizar una posible solución en el archivo ubicado en esta ruta: 1_programacion_orientada_a_objetos/soluciones/herencia/solucion.py
En la carpeta ejercicios\polimorfismo
en esta misma ruta, se encuentra el archivo llamado polimorfismo en el cual deberás crear una clase base Empleado con un método calcular_bonus() que devuelva 0.
Luego crea dos subclases:
- Desarrollador, que tiene un sueldo base y su bonus es el 20% del sueldo.
- Gerente, que tiene un sueldo base y su bonus es el 50% del sueldo.
Ambas clases deben sobrescribir calcular_bonus().
Finalmente, crea una función llamada calcular_total_bonos que reciba una lista de empleados y calcule el total de bonos.
Una vez hayas creado la clase y sus métodos, deberás ejecutar los test unitarios para validar correctamente la implementación. En la consola de comandos deberás ejecutar el siguiente comando posicionado en dicha ruta:
1py test_polimorfismo.py polimorfismo
Una vez hayas realizado la actividad puedes visualizar una posible solución en el archivo ubicado en esta ruta: 1_programacion_orientada_a_objetos/soluciones/polimorfismo/solucion.py