Proyectos Prácticos. Hasta ahora hemos explorado los fundamentos de la programación en Python, desde estructuras básicas hasta programación funcional, manejo de errores, módulos, y gestión y depuración de la memoria. Es la hora de llevar este conocimiento a la práctica mediante proyectos completos. Estos ejercicios te permitirán consolidar tus habilidades.
A parte de estos ejercicios prácticos que te proponemos existe amplia bilbiogrofaía para practicar, te podemos aconsejar el siguiente libro: 100 Ejercicios Python para praticar. Autor: Laurentine K.Masson (Editorial: Publicación Independiente).
Empezemos.
Proyecto 1: Calculadora Básica
Enunciado:
Crea un programa en Python que implemente una calculadora básica. La calculadora debe permitir al usuario realizar operaciones como suma, resta, multiplicación, división, y potencia.
El programa debe:
- Solicitar al usuario que seleccione una operación (suma, resta, multiplicación, división, potencia, o salir).
- Pedir al usuario que introduzca dos números para realizar la operación.
- Realizar la operación y mostrar el resultado.
- Manejar posibles errores, como divisiones entre cero o entradas no válidas.
- Repetirse hasta que el usuario elija salir.
Código Completo:
def mostrar_menu():
print("=== Calculadora Básica ===")
print("1. Sumar")
print("2. Restar")
print("3. Multiplicar")
print("4. Dividir")
print("5. Potencia")
print("6. Salir")
def suma(a, b):
return a + b
def resta(a, b):
return a - b
def multiplicacion(a, b):
return a * b
def division(a, b):
if b == 0:
return "Error: División por cero no permitida."
return a / b
def potencia(a, b):
return a ** b
def calculadora():
while True:
mostrar_menu()
try:
opcion = int(input("Selecciona una operación (1-6): "))
if opcion == 6:
print("¡Gracias por usar la calculadora!")
break
elif 1 <= opcion <= 5:
num1 = float(input("Introduce el primer número: "))
num2 = float(input("Introduce el segundo número: "))
if opcion == 1:
print(f"Resultado: {suma(num1, num2)}")
elif opcion == 2:
print(f"Resultado: {resta(num1, num2)}")
elif opcion == 3:
print(f"Resultado: {multiplicacion(num1, num2)}")
elif opcion == 4:
print(f"Resultado: {division(num1, num2)}")
elif opcion == 5:
print(f"Resultado: {potencia(num1, num2)}")
else:
print("Opción no válida. Por favor, selecciona entre 1 y 6.")
except ValueError:
print("Entrada no válida. Por favor, introduce un número.")
# Ejecutar la calculadora
calculadora()
Explicación del Programa:
- Estructura del programa:
- El programa está dividido en funciones para modularizar el código:
mostrar_menu()
: Presenta las opciones disponibles al usuario.- Una función para cada operación matemática (
suma
,resta
,multiplicacion
,division
,potencia
). calculadora()
: Función principal que gestiona la lógica del programa.
- El programa está dividido en funciones para modularizar el código:
- Funcionalidad:
- Interacción con el usuario:
El usuario selecciona una opción del menú e introduce dos números. Dependiendo de la opción elegida, se llama a la función correspondiente para realizar la operación. - Control de errores:
- División por cero: La función
division
comprueba si el divisor es cero y devuelve un mensaje de error en lugar de intentar dividir. - Entradas no válidas: El programa usa un bloque
try-except
para manejar errores como introducir texto en lugar de números.
- División por cero: La función
- Interacción con el usuario:
- Lógica de salida:
- Si el usuario selecciona la opción 6, el programa imprime un mensaje de despedida y termina.
- Repetición:
- El programa está dentro de un bucle
while True
, lo que permite que la calculadora siga funcionando hasta que el usuario elija salir.
- El programa está dentro de un bucle
Prueba del Programa:
- Entrada:
- Opción:
1
- Números:
5
y10
- Opción:
- Salida:
Resultado: 15
- Entrada:
- Opción:
4
- Números:
5
y0
- Opción:
- Salida:
Error: División por cero no permitida.
Este proyecto te ayudará a practicar estructuras de control, funciones, manejo de excepciones, y la interacción con el usuario.
Proyecto 2: Manejo de Clases – Clase Televisor
Enunciado Completo:
Crea un programa en Python que modele un televisor utilizando programación orientada a objetos. La clase Televisor
debe incluir atributos para propiedades comunes como volumen, canal, brillo y contraste. También debe tener métodos para realizar las siguientes acciones:
- Cambiar de canal (subir o bajar).
- Ajustar el volumen (subir o bajar).
- Modificar brillo y contraste.
- Mostrar el estado actual del televisor (atributos como canal, volumen, brillo, etc.).
- Encender y apagar el televisor.
El programa debe:
- Crear una instancia de la clase
Televisor
. - Permitir al usuario interactuar con el televisor a través de un menú, realizando las acciones descritas.
- Validar las entradas del usuario (por ejemplo, no permitir que el volumen supere un límite).
Código Completo:
class Televisor:
def __init__(self, max_volumen=100, max_canal=50):
self.encendido = False
self.canal = 1
self.volumen = 10
self.brillo = 50
self.contraste = 50
self.max_volumen = max_volumen
self.max_canal = max_canal
def encender_apagar(self):
self.encendido = not self.encendido
estado = "encendido" if self.encendido else "apagado"
print(f"El televisor está {estado}.")
def cambiar_canal(self, direccion):
if self.encendido:
if direccion == "subir" and self.canal < self.max_canal:
self.canal += 1
elif direccion == "bajar" and self.canal > 1:
self.canal -= 1
print(f"Canal actual: {self.canal}")
else:
print("El televisor está apagado.")
def ajustar_volumen(self, direccion):
if self.encendido:
if direccion == "subir" and self.volumen < self.max_volumen:
self.volumen += 1
elif direccion == "bajar" and self.volumen > 0:
self.volumen -= 1
print(f"Volumen actual: {self.volumen}")
else:
print("El televisor está apagado.")
def ajustar_brillo(self, nuevo_brillo):
if self.encendido:
self.brillo = max(0, min(100, nuevo_brillo))
print(f"Brillo ajustado a: {self.brillo}")
else:
print("El televisor está apagado.")
def ajustar_contraste(self, nuevo_contraste):
if self.encendido:
self.contraste = max(0, min(100, nuevo_contraste))
print(f"Contraste ajustado a: {self.contraste}")
else:
print("El televisor está apagado.")
def mostrar_estado(self):
if self.encendido:
print(f"Estado del Televisor:")
print(f" Canal: {self.canal}")
print(f" Volumen: {self.volumen}")
print(f" Brillo: {self.brillo}")
print(f" Contraste: {self.contraste}")
else:
print("El televisor está apagado.")
# Menú principal para interactuar con el televisor
def menu_televisor():
televisor = Televisor()
while True:
print("\n=== Menú del Televisor ===")
print("1. Encender/Apagar")
print("2. Subir canal")
print("3. Bajar canal")
print("4. Subir volumen")
print("5. Bajar volumen")
print("6. Ajustar brillo")
print("7. Ajustar contraste")
print("8. Mostrar estado")
print("9. Salir")
try:
opcion = int(input("Selecciona una opción: "))
if opcion == 1:
televisor.encender_apagar()
elif opcion == 2:
televisor.cambiar_canal("subir")
elif opcion == 3:
televisor.cambiar_canal("bajar")
elif opcion == 4:
televisor.ajustar_volumen("subir")
elif opcion == 5:
televisor.ajustar_volumen("bajar")
elif opcion == 6:
nuevo_brillo = int(input("Introduce el nuevo brillo (0-100): "))
televisor.ajustar_brillo(nuevo_brillo)
elif opcion == 7:
nuevo_contraste = int(input("Introduce el nuevo contraste (0-100): "))
televisor.ajustar_contraste(nuevo_contraste)
elif opcion == 8:
televisor.mostrar_estado()
elif opcion == 9:
print("Saliendo del programa...")
break
else:
print("Opción no válida.")
except ValueError:
print("Entrada no válida. Intenta de nuevo.")
# Ejecutar el programa
menu_televisor()
Explicación del Programa:
- Clase
Televisor
:- Define atributos como
volumen
,canal
,brillo
, ycontraste
, con valores iniciales predeterminados. - Incluye un atributo
encendido
para rastrear si el televisor está encendido o apagado. - Métodos como
encender_apagar
,cambiar_canal
,ajustar_volumen
, y ajustes para brillo y contraste permiten modificar los atributos según la acción del usuario.
- Define atributos como
- Menú Interactivo:
- Ofrece opciones al usuario para interactuar con el televisor.
- Usa un bucle para permitir acciones continuas hasta que el usuario decida salir.
- Realiza validaciones básicas para evitar errores, como introducir valores no válidos.
Pruebas del Programa:
Caso 1:
Entrada: Encender el televisor, subir el canal dos veces, y mostrar estado.
Salida:
El televisor está encendido.
Canal actual: 2
Canal actual: 3
Estado del Televisor:
Canal: 3
Volumen: 10
Brillo: 50
Contraste: 50
Caso 2:
Entrada: Ajustar brillo a 75 y apagar el televisor.
Salida:
Brillo ajustado a: 75
El televisor está apagado.
Conclusión:
Este proyecto permite practicar conceptos fundamentales de Programación Orientada a Objetos como:
- Atributos y Métodos: Representan el estado y el comportamiento de una clase.
- Encapsulación: Los datos están protegidos dentro de la clase.
- Interacción Dinámica: La clase es fácil de usar gracias al menú interactivo.
Este ejercicio también refuerza la validación de entradas y el manejo de bucles para interacción continua.
Proyecto 3: Base de Datos de Empleados
Enunciado
En este proyecto, se hay que desarrollar un programa en Python que modele un sistema de gestión de empleados con una base de datos persistente almacenada en un archivo.
El programa debe incluir:
- Una clase
Empleado
que represente a cada empleado, con atributos como:id
(único para cada empleado).nombre
.edad
.puesto
.salario
.
- Una clase
BBDD
para gestionar la base de datos, que implemente las siguientes funcionalidades:- Añadir empleado: Crear un nuevo registro.
- Borrar empleado: Eliminar un empleado por su ID.
- Modificar empleado: Actualizar los datos de un empleado existente.
- Listar empleados: Mostrar todos los empleados registrados.
- Los datos deben almacenarse en un archivo JSON para asegurar su persistencia.
- El programa debe ofrecer un menú interactivo para realizar estas operaciones.
Código
import json
class Empleado:
def __init__(self, id, nombre, edad, puesto, salario):
self.id = id
self.nombre = nombre
self.edad = edad
self.puesto = puesto
self.salario = salario
def to_dict(self):
"""Convierte el objeto Empleado a un diccionario para su almacenamiento."""
return {
"id": self.id,
"nombre": self.nombre,
"edad": self.edad,
"puesto": self.puesto,
"salario": self.salario
}
class BBDD:
def __init__(self, archivo='empleados.json'):
self.archivo = archivo
self.empleados = self.cargar_datos()
def cargar_datos(self):
"""Carga los datos del archivo JSON."""
try:
with open(self.archivo, 'r') as file:
return json.load(file)
except FileNotFoundError:
return []
def guardar_datos(self):
"""Guarda los datos actuales en el archivo JSON."""
with open(self.archivo, 'w') as file:
json.dump(self.empleados, file, indent=4)
def añadir_empleado(self, empleado):
"""Añade un empleado a la base de datos."""
self.empleados.append(empleado.to_dict())
self.guardar_datos()
print("Empleado añadido con éxito.")
def borrar_empleado(self, id):
"""Elimina un empleado por su ID."""
for emp in self.empleados:
if emp['id'] == id:
self.empleados.remove(emp)
self.guardar_datos()
print(f"Empleado con ID {id} eliminado.")
return
print("Empleado no encontrado.")
def modificar_empleado(self, id, campo, nuevo_valor):
"""Modifica un campo de un empleado específico."""
for emp in self.empleados:
if emp['id'] == id:
if campo in emp:
emp[campo] = nuevo_valor
self.guardar_datos()
print(f"Empleado con ID {id} actualizado.")
return
else:
print("Campo no válido.")
return
print("Empleado no encontrado.")
def listar_empleados(self):
"""Lista todos los empleados en la base de datos."""
if self.empleados:
for emp in self.empleados:
print(f"ID: {emp['id']}, Nombre: {emp['nombre']}, Edad: {emp['edad']}, "
f"Puesto: {emp['puesto']}, Salario: {emp['salario']}")
else:
print("No hay empleados registrados.")
# Menú principal
def menu_principal():
bbdd = BBDD()
while True:
print("\n=== Menú de Gestión de Empleados ===")
print("1. Añadir Empleado")
print("2. Borrar Empleado")
print("3. Modificar Empleado")
print("4. Listar Empleados")
print("5. Salir")
try:
opcion = int(input("Selecciona una opción: "))
if opcion == 1:
id = input("ID: ")
nombre = input("Nombre: ")
edad = int(input("Edad: "))
puesto = input("Puesto: ")
salario = float(input("Salario: "))
empleado = Empleado(id, nombre, edad, puesto, salario)
bbdd.añadir_empleado(empleado)
elif opcion == 2:
id = input("Introduce el ID del empleado a eliminar: ")
bbdd.borrar_empleado(id)
elif opcion == 3:
id = input("Introduce el ID del empleado a modificar: ")
campo = input("Campo a modificar (nombre, edad, puesto, salario): ")
nuevo_valor = input("Nuevo valor: ")
if campo in ['edad', 'salario']:
nuevo_valor = float(nuevo_valor) if campo == 'salario' else int(nuevo_valor)
bbdd.modificar_empleado(id, campo, nuevo_valor)
elif opcion == 4:
bbdd.listar_empleados()
elif opcion == 5:
print("Saliendo del programa...")
break
else:
print("Opción no válida.")
except ValueError:
print("Entrada no válida. Inténtalo de nuevo.")
# Ejecutar el programa
menu_principal()
Explicación del Código
Clase Empleado
:
Representa a un empleado.
Incluye un método to_dict
para convertir los datos a un formato adecuado para almacenar en JSON.
Clase BBDD
:
Maneja la persistencia de datos usando un archivo JSON.
Métodos como añadir_empleado
, borrar_empleado
, modificar_empleado
, y listar_empleados
ofrecen una API para interactuar con la base de datos.
Archivo JSON:
Se utiliza para almacenar la información de manera persistente.
Menú Interactivo:
Permite al usuario interactuar con las funcionalidades de la base de datos.
Pruebas
Caso 1:
- Entrada: Añadir un empleado con ID
001
, nombreJuan Pérez
, edad30
, puestoAnalista
, salario50000
. - Salida:
Empleado añadido con éxito.
Caso 2:
- Entrada: Listar empleados después del caso 1.
- Salida:
ID: 001, Nombre: Juan Pérez, Edad: 30, Puesto: Analista, Salario: 50000
Caso 3:
- Entrada: Modificar el salario del empleado con ID
001
a55000
. - Salida:
Empleado con ID 001 actualizado.
Conclusión del Proyecto
Este proyecto refuerza los siguientes conceptos:
- Clases y Objetos: Modelado del dominio mediante clases (
Empleado
yBBDD
). - Persistencia de Datos: Uso de JSON para almacenar y recuperar información.
- Interacción Usuario-Sistema: Implementación de un menú dinámico.
- Validación: Manejo de errores básicos y restricciones en entradas del usuario.
Este enfoque simula un sistema práctico utilizado en aplicaciones del mundo real, como sistemas de gestión de empleados.
Proyecto 4: Manejo de Archivos CSV – Datos de Temperatura y Viento
Enunciado
En este proyecto, vamos a trabajar con archivos CSV para gestionar datos meteorológicos (temperatura y velocidad del viento) en las provincias de España. El programa permitirá:
- Añadir datos: Registrar información de temperatura y viento para una provincia.
- Borrar datos: Eliminar los registros de una provincia específica.
- Modificar datos: Actualizar la información de temperatura o viento para una provincia.
- Listar datos: Mostrar todos los registros almacenados.
- Generar reportes:
- Mostrar la provincia con la temperatura más alta.
- Mostrar la provincia con la velocidad del viento más baja.
Los datos deben almacenarse en un archivo CSV para asegurar su persistencia. El programa tendrá un menú interactivo para realizar estas operaciones.
Código
import csv
class DatosMeteorologicos:
def __init__(self, archivo='meteorologia.csv'):
self.archivo = archivo
self.campos = ['Provincia', 'Temperatura', 'Viento']
# Crear el archivo si no existe
try:
with open(self.archivo, 'x', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=self.campos)
writer.writeheader()
except FileExistsError:
pass
def añadir_datos(self, provincia, temperatura, viento):
"""Añade datos meteorológicos de una provincia al archivo CSV."""
with open(self.archivo, 'a', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=self.campos)
writer.writerow({
'Provincia': provincia,
'Temperatura': temperatura,
'Viento': viento
})
print(f"Datos de {provincia} añadidos con éxito.")
def borrar_datos(self, provincia):
"""Borra los datos de una provincia específica."""
registros_actualizados = []
encontrado = False
with open(self.archivo, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for fila in reader:
if fila['Provincia'].lower() != provincia.lower():
registros_actualizados.append(fila)
else:
encontrado = True
if encontrado:
with open(self.archivo, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=self.campos)
writer.writeheader()
writer.writerows(registros_actualizados)
print(f"Datos de {provincia} eliminados con éxito.")
else:
print(f"No se encontraron datos para la provincia {provincia}.")
def modificar_datos(self, provincia, campo, nuevo_valor):
"""Modifica los datos meteorológicos de una provincia."""
registros_actualizados = []
encontrado = False
with open(self.archivo, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for fila in reader:
if fila['Provincia'].lower() == provincia.lower():
fila[campo] = nuevo_valor
encontrado = True
registros_actualizados.append(fila)
if encontrado:
with open(self.archivo, 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=self.campos)
writer.writeheader()
writer.writerows(registros_actualizados)
print(f"Datos de {provincia} actualizados con éxito.")
else:
print(f"No se encontraron datos para la provincia {provincia}.")
def listar_datos(self):
"""Muestra todos los datos del archivo CSV."""
print("\n=== Datos Meteorológicos ===")
with open(self.archivo, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for fila in reader:
print(f"Provincia: {fila['Provincia']}, Temperatura: {fila['Temperatura']}°C, Viento: {fila['Viento']} km/h")
def generar_reportes(self):
"""Genera reportes sobre los datos almacenados."""
temperaturas = []
vientos = []
with open(self.archivo, 'r', newline='', encoding='utf-8') as file:
reader = csv.DictReader(file)
for fila in reader:
temperaturas.append((fila['Provincia'], float(fila['Temperatura'])))
vientos.append((fila['Provincia'], float(fila['Viento'])))
if temperaturas and vientos:
provincia_max_temp = max(temperaturas, key=lambda x: x[1])
provincia_min_viento = min(vientos, key=lambda x: x[1])
print("\n=== Reportes ===")
print(f"Provincia con la temperatura más alta: {provincia_max_temp[0]} ({provincia_max_temp[1]}°C)")
print(f"Provincia con la velocidad de viento más baja: {provincia_min_viento[0]} ({provincia_min_viento[1]} km/h)")
else:
print("No hay datos suficientes para generar reportes.")
# Menú principal
def menu_principal():
gestor = DatosMeteorologicos()
while True:
print("\n=== Menú de Gestión de Datos Meteorológicos ===")
print("1. Añadir datos")
print("2. Borrar datos")
print("3. Modificar datos")
print("4. Listar datos")
print("5. Generar reportes")
print("6. Salir")
try:
opcion = int(input("Selecciona una opción: "))
if opcion == 1:
provincia = input("Provincia: ")
temperatura = float(input("Temperatura (°C): "))
viento = float(input("Velocidad del viento (km/h): "))
gestor.añadir_datos(provincia, temperatura, viento)
elif opcion == 2:
provincia = input("Introduce la provincia a eliminar: ")
gestor.borrar_datos(provincia)
elif opcion == 3:
provincia = input("Introduce la provincia a modificar: ")
campo = input("Campo a modificar (Temperatura o Viento): ").capitalize()
nuevo_valor = float(input(f"Nuevo valor para {campo}: "))
gestor.modificar_datos(provincia, campo, nuevo_valor)
elif opcion == 4:
gestor.listar_datos()
elif opcion == 5:
gestor.generar_reportes()
elif opcion == 6:
print("Saliendo del programa...")
break
else:
print("Opción no válida.")
except ValueError:
print("Entrada no válida. Inténtalo de nuevo.")
# Ejecutar el programa
menu_principal()
Explicación del Código
- Clase
DatosMeteorologicos
:- Administra los datos meteorológicos en un archivo CSV.
- Implementa métodos para añadir, borrar, modificar, listar datos y generar reportes.
- Usa el módulo
csv
para leer y escribir en el archivo.
- Archivo CSV:
- Los datos se guardan en formato CSV para garantizar la persistencia.
- El archivo se crea automáticamente si no existe.
- Menú Interactivo:
- Ofrece una interfaz para interactuar con las funcionalidades del sistema.
Pruebas
Caso 1:
- Entrada: Añadir datos para
Madrid
con temperatura30°C
y viento15 km/h
. - Salida:
Datos de Madrid añadidos con éxito.
Caso 2:
- Entrada: Listar datos después del caso 1.
- Salida:
Provincia: Madrid, Temperatura: 30.0°C, Viento: 15.0 km/h
Caso 3:
- Entrada: Generar reportes después de añadir datos para
Barcelona
con temperatura25°C
y viento10 km/h
. - Salida:
Provincia con la temperatura más alta: Madrid (30.0°C) Provincia con la velocidad de viento más baja: Barcelona (10.0 km/h)
Conclusión del Proyecto
Este proyecto refuerza:
- Uso del módulo
csv
: Leer y escribir datos en archivos CSV. - Estructuración: División lógica en métodos específicos para cada funcionalidad.
- Análisis de datos: Generar reportes básicos basados en los datos almacenados.
- Validación y persistencia: Validar entradas y mantener datos de forma persistente.
Bibliografía de Python de interés.
- Curso de Programación Python. Autor: Arturo Montejo Ráez y Salud María Jiménez Zafra (Editorial Anaya)
- Aprende Python desde cero hasta avanzado. Autor: Xavier Reyes Ochoa (Editorial Book Shelter GmbH)
- Aprende la Programación Orientada a Objetos con el lenguaje Python. Autor: Vincent Boucheny (Editorial Ediciones ENI)
- 100 Ejercicios Python para praticar. Autor: Laurentine K.Masson (Editorial: Publicación Independiente).