================================== Sesión 7 - Módulos y Recursividad ================================== 1. Módulos y Paquetes en Python ------------------------------- 1.1 Introducción a los Módulos ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Un **módulo** es un archivo que contiene código Python reutilizable: * Ventajas: * Organización del código * Reutilización * Mantenimiento simplificado * Espacios de nombres separados 1.2 Formas de Importación ~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python # Importación básica import math print(math.sqrt(16)) # 4.0 # Importación específica from math import sqrt print(sqrt(16)) # 4.0 # Importación con alias import math as m print(m.sqrt(16)) # 4.0 # Importación múltiple from math import sqrt, pi print(sqrt(16), pi) # 4.0 3.141592653589793 # Importación total (no recomendada en general) from math import * print(sqrt(16), pi) # 4.0 3.141592653589793 1.3 Módulos Estándar Principales ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Python incluye una amplia biblioteca estándar con numerosos módulos útiles: .. list-table:: Módulos Estándar Principales :header-rows: 1 :widths: 15 55 30 * - Módulo - Descripción - Documentación * - ``math`` - Funciones matemáticas (trigonometría, logaritmos, etc.) - `Documentación math `_ * - ``random`` - Generación de números aleatorios - `Documentación random `_ * - ``time`` - Acceso a tiempo, conversiones y mediciones - `Documentación time `_ * - ``sys`` - Interacción con el intérprete de Python - `Documentación sys `_ * - ``os`` - Interacción con el sistema operativo y sistema de archivos - `Documentación os `_ * - ``datetime`` - Manipulación de fechas y horas - `Documentación datetime `_ * - ``json`` - Codificación y decodificación de datos JSON - `Documentación json `_ * - ``re`` - Expresiones regulares para procesamiento de texto - `Documentación re `_ * - ``collections`` - Estructuras de datos especializadas - `Documentación collections `_ * - ``statistics`` - Funciones estadísticas (media, mediana, desviación, etc.) - `Documentación statistics `_ * - ``pathlib`` - Manejo de rutas de sistema de archivos orientado a objetos - `Documentación pathlib `_ Para una descripción detallada y ejemplos, consultaremos algunos módulos específicos: **Módulo math - funciones matemáticas** .. code-block:: python import math print(f"Pi aproximado: {math.pi}") print(f"Seno de 30°: {math.sin(math.radians(30))}") **Módulo random - generación de números aleatorios** .. code-block:: python import random print(f"Número aleatorio entre 1 y 10: {random.randint(1, 10)}") print(f"Elemento aleatorio de una lista: {random.choice(['rojo', 'verde', 'azul'])}") **Módulo time - funciones relacionadas con el tiempo** .. code-block:: python import time inicio = time.time() time.sleep(1) # Pausa de 1 segundo fin = time.time() print(f"Tiempo transcurrido: {fin - inicio} segundos") **Módulo sys - interacción con el intérprete** .. code-block:: python import sys print(f"Argumentos de línea de comando: {sys.argv}") .. code-block:: python import sys print(f"Versión de Python: {sys.version}") print(f"Ruta de búsqueda de módulos: {sys.path}") .. code-block:: python import sys # sys.exit(0) # Código 0 indica finalización exitosa # sys.exit(1) # Código diferente de 0 indica error sys.exit(1) # Descomentar para probar (código 1 indica error) **Recurso global:** Para explorar todos los módulos de la biblioteca estándar, consulte la `Referencia de la Biblioteca de Python `_. 1.4 Creación de Módulos Propios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Archivo ``geometria.py``: .. code-block:: python # geometria.py def area_rectangulo(base, altura): return base * altura def area_triangulo(base, altura): return (base * altura) / 2 def area_circulo(radio): import math return math.pi * radio ** 2 Uso del módulo: .. code-block:: python # uso_geometria.py import geometria print(f"Área de un rectángulo de 5x3: {geometria.area_rectangulo(5, 3)}") print(f"Área de un triángulo de base 4 y altura 6: {geometria.area_triangulo(4, 6)}") print(f"Área de un círculo de radio 2: {geometria.area_circulo(2)}") .. code-block:: python """ Este es un módulo de ejemplo. Contiene funciones y variables que pueden ser importadas. """ def saludar(nombre): """Saluda a una persona por su nombre.""" return f"Hola, {nombre}!" def despedir(): """Se despide del usuario.""" return "¡Hasta pronto!" # Variable del módulo PI = 3.14159 # La construcción if __name__ == "__main__" permite ejecutar código # solo cuando el archivo se ejecuta directamente, no cuando se importa. if __name__ == "__main__": # Este código solo se ejecutará si el archivo se ejecuta directamente print("Este módulo se está ejecutando directamente") print(saludar("Usuario")) print(f"El valor de PI es: {PI}") else: # Este código se ejecutará cuando el módulo sea importado print("El módulo ha sido importado") 1.5 Paquetes ============ Un paquete es una forma de organizar módulos relacionados en una estructura de directorios. Ejemplo de estructura de paquete: .. code-block:: text matematicas/ __init__.py aritmetica.py geometria/ __init__.py figuras_2d.py figuras_3d.py El archivo ``__init__.py`` es necesario para que Python trate el directorio como un paquete. Puede estar vacío, pero indica a Python que el directorio debe tratarse como un paquete. Ejemplo de contenido para los módulos: .. code-block:: python # aritmetica.py def suma(a, b): return a + b def resta(a, b): return a - b .. code-block:: python # geometria/figuras_2d.py import math def area_circulo(radio): return math.pi * radio ** 2 def area_rectangulo(base, altura): return base * altura Para importar desde un paquete: .. code-block:: python from matematicas.aritmetica import suma, resta from matematicas.geometria.figuras_2d import area_circulo import matematicas.geometria.figuras_2d as figuras2d ¿Qué se puede hacer con el archivo __init__.py? ---------------------------------------------- El archivo ``__init__.py`` puede contener código que se ejecutará cuando el paquete sea importado. Algunos usos comunes para nuestro ejemplo de matemáticas serían: .. code-block:: python # Ejemplo de contenido para matematicas/__init__.py: # 1. Exponer funciones principales directamente desde el paquete from .aritmetica import suma, resta from .geometria.figuras_2d import area_circulo, area_rectangulo # 2. Definir constantes útiles PI = 3.14159265359 # 3. Controlar qué se importa con "from matematicas import *" __all__ = ['suma', 'resta', 'area_circulo', 'area_rectangulo', 'PI'] # 4. Información sobre el paquete __version__ = '1.0.0' Con el ``__init__.py`` anterior, podríamos hacer: .. code-block:: python from matematicas import suma, area_circulo, PI directamente, sin necesidad de importar de los submódulos específicos. 2. Recursividad en Python ------------------------- 2.1 Concepto de Recursividad ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ La **recursividad** es un concepto donde una función se llama a sí misma: * Componentes esenciales: * **Caso base**: condición que detiene la recursión * **Caso recursivo**: llamada a la misma función con un problema menor * La recursividad permite simplificar problemas complejos dividiéndolos en problemas más pequeños. 2.2 Ejemplo Clásico: Factorial ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python def factorial(n): # Caso base if n == 0 or n == 1: return 1 # Caso recursivo else: return n * factorial(n-1) # Pruebas for i in range(6): print(f"{i}! = {factorial(i)}") Flujo de ejecución paso a paso con n=4: .. code-block:: text factorial(4) → 4 * factorial(3) factorial(3) → 3 * factorial(2) factorial(2) → 2 * factorial(1) factorial(1) → 1 (caso base) Retornando: 1 → 2*1=2 → 3*2=6 → 4*6=24 2.3 Ejemplo: Secuencia de Fibonacci ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python def fibonacci(n): # Casos base if n <= 0: return 0 elif n == 1: return 1 # Caso recursivo else: return fibonacci(n-1) + fibonacci(n-2) # Primeros 10 números de Fibonacci for i in range(10): print(f"Fibonacci({i}) = {fibonacci(i)}") 2.4 Consideraciones y Limitaciones ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: python import sys print(f"Límite de recursión actual: {sys.getrecursionlimit()}") sys.setrecursionlimit(2000) # Aumentar el límite print(f"Nuevo límite de recursión: {sys.getrecursionlimit()}") Limitaciones importantes: * Python limita la profundidad de recursión (normalmente 1000) * La recursión consume memoria de la pila (stack) * La recursión puede ser ineficiente para ciertos problemas (ej: Fibonacci) Segunda Hora: Ejercicios Prácticos ================================== 1. Ejercicios sobre Módulos y Paquetes ------------------------------------ Ejercicio 1: Uso de Módulos Estándar ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear un script que: * Genere 10 números aleatorios entre 1 y 100 * Calcule y muestre estadísticas: mínimo, máximo, promedio, desviación estándar * Utilice los módulos: ``random``, ``statistics`` y ``math`` Estructura básica: .. code-block:: python # Estructura básica para empezar import random import statistics import math # Generar números aleatorios # Calcular estadísticas # Mostrar resultados Ejercicio 2: Creación de un Módulo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Crear un módulo ``fisica.py`` con funciones para calcular: * Velocidad (distancia/tiempo) * Aceleración (cambio de velocidad/tiempo) * Energía cinética (1/2 * masa * velocidad^2) * Crear un script principal que importe y use estas funciones con ejemplos Ejercicio 3: Creación de un Paquete Simple ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Crear un paquete llamado ``utils`` con la siguiente estructura: .. code-block:: text utils/ ├── __init__.py ├── matematicas.py └── texto.py * En ``matematicas.py``, implementar funciones para operaciones básicas * En ``texto.py``, implementar funciones para procesar texto (ej: contar palabras) * Crear un script que importe y use funciones de ambos módulos 2. Ejercicios sobre Recursividad ------------------------------- Ejercicio 4: Potencia Recursiva ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Implementar una función recursiva para calcular x^n (sin utilizar el operador ``**``). .. code-block:: python def potencia(x, n): # Completar aquí pass # Pruebas print(potencia(2, 3)) # Debería ser 8 print(potencia(5, 2)) # Debería ser 25 Ejercicio 5: Suma de Lista Recursiva ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear una función recursiva que sume todos los elementos de una lista. .. code-block:: python def suma_lista(lista): # Completar aquí pass # Pruebas print(suma_lista([1, 2, 3, 4, 5])) # Debería ser 15 print(suma_lista([])) # Debería ser 0 Ejercicio 6: Palíndromo Recursivo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear una función recursiva que verifique si una cadena es un palíndromo. .. code-block:: python def es_palindromo(texto): # Completar aquí pass # Pruebas print(es_palindromo("radar")) # True print(es_palindromo("python")) # False Ejercicio 7: Búsqueda Recursiva ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Implementar una función recursiva que busque un elemento en una lista y devuelva su índice (o -1 si no existe). .. code-block:: python def buscar(lista, elemento, indice=0): # Completar aquí pass # Pruebas print(buscar([1, 4, 7, 2, 5], 7)) # Debería ser 2 print(buscar([1, 4, 7, 2, 5], 9)) # Debería ser -1 Ejercicios Adicionales para Trabajo en Casa ========================================== 1. Ejercicios sobre Módulos y Paquetes ------------------------------------ Ejercicio A: Calculadora de Tiempo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear un módulo para convertir entre diferentes unidades de tiempo (segundos, minutos, horas, días) y un programa que lo utilice. Ejercicio B: Manipulación de Archivos ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear un módulo con funciones para leer, escribir y analizar archivos de texto, luego usarlo para procesar un archivo de ejemplo. Ejercicio C: Paquete Completo ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Crear un paquete para simulación robótica simple con la siguiente estructura: .. code-block:: text robot_sim/ ├── __init__.py ├── movimiento.py # Funciones para calcular movimiento ├── sensores.py # Simulación de lecturas de sensores └── utils/ ├── __init__.py └── graficos.py # Funciones para visualizar datos Implementar al menos 2-3 funciones en cada módulo y crear un script principal que demuestre todas las funcionalidades. 2. Ejercicios sobre Recursividad ------------------------------- Ejercicio D: MCD Recursivo ~~~~~~~~~~~~~~~~~~~~~~~~~ Implementar el algoritmo de Euclides para encontrar el máximo común divisor recursivamente. .. code-block:: python def mcd(a, b): # Completar aquí pass # Pruebas print(mcd(48, 18)) # Debería ser 6 print(mcd(101, 103)) # Debería ser 1 Ejercicio E: Recorrido Recursivo de Directorios ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Usar la recursividad para listar todos los archivos en un directorio y sus subdirectorios (usar el módulo ``os``). .. code-block:: python def listar_archivos(ruta): # Completar aquí pass # Ejecutar en el directorio actual archivos = listar_archivos("./") for archivo in archivos[:5]: # Mostrar solo los primeros 5 print(archivo) Recursos Adicionales =================== * Documentación oficial de Python sobre módulos: https://docs.python.org/3/tutorial/modules.html * Documentación sobre paquetes: https://docs.python.org/3/tutorial/modules.html#packages * Documentación sobre los módulos estándar: https://docs.python.org/3/library/ * Visualizador de recursión: https://www.pythontutor.com/ * Blog sobre recursividad en Python: https://realpython.com/python-recursion/