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

# 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:

Módulos Estándar Principales

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

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

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

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

import sys
print(f"Argumentos de línea de comando: {sys.argv}")
import sys
print(f"Versión de Python: {sys.version}")
print(f"Ruta de búsqueda de módulos: {sys.path}")
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:

# 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:

# 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)}")
"""
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:

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:

# aritmetica.py
def suma(a, b):
    return a + b

def resta(a, b):
    return a - b
# 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:

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:

# 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:

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

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:

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

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

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:

# 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:

    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 **).

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.

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.

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).

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:

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.

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).

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