05. Funciones y Módulos
Crea funciones reutilizables y organiza tu código profesionalmente
Aprende a crear funciones reutilizables y organizar tu código profesionalmente con módulos. Las funciones son el corazón de la programación eficiente.
¿Por qué usar funciones?
Las funciones te permiten:
- ✅ Reutilizar código: Escribe una vez, usa muchas veces
- ✅ Organización: Código más limpio y mantenible
- ✅ Testing: Fácil de probar y debuggear
- ✅ Colaboración: Otros entienden tu código rápidamente
Crear funciones básicas
Sintaxis fundamental
def nombre_funcion():
"""Docstring: explica qué hace la función"""
# Código de la función
print("Hola desde la función")
# Llamar a la función
nombre_funcion()
Funciones con parámetros
def saludar(nombre):
"""Saluda a una persona por su nombre"""
print(f"Hola, {nombre}!")
saludar("María") # Hola, María!
saludar("Carlos") # Hola, Carlos!
Funciones que retornan valores
def calcular_iva(precio, tasa_iva=0.21):
"""
Calcula el IVA de un precio.
Args:
precio: Precio base sin IVA
tasa_iva: Tasa de IVA (default 21%)
Returns:
Precio total con IVA incluido
"""
iva = precio * tasa_iva
total = precio + iva
return total
precio_final = calcular_iva(100)
print(f"Precio con IVA: ${precio_final}") # $121.0
# Usar tasa diferente
precio_final_reducido = calcular_iva(100, 0.10)
print(f"Precio con IVA reducido: ${precio_final_reducido}") # $110.0
Funciones para análisis de datos
Calcular métricas de campaña
def calcular_metricas_campaña(impresiones, clics, conversiones, costo):
"""
Calcula métricas clave de una campaña digital.
Returns:
dict: Diccionario con todas las métricas calculadas
"""
ctr = (clics / impresiones) * 100 if impresiones > 0 else 0
conversion_rate = (conversiones / clics) * 100 if clics > 0 else 0
cpc = costo / clics if clics > 0 else 0
cpa = costo / conversiones if conversiones > 0 else 0
return {
"ctr": round(ctr, 2),
"conversion_rate": round(conversion_rate, 2),
"cpc": round(cpc, 2),
"cpa": round(cpa, 2)
}
# Usar la función
metricas = calcular_metricas_campaña(
impresiones=100000,
clics=3000,
conversiones=150,
costo=1500
)
print("Métricas de campaña:")
print(f" CTR: {metricas['ctr']}%")
print(f" Conversion Rate: {metricas['conversion_rate']}%")
print(f" CPC: ${metricas['cpc']}")
print(f" CPA: ${metricas['cpa']}")
Resultado:
Métricas de campaña:
CTR: 3.0%
Conversion Rate: 5.0%
CPC: $0.5
CPA: $10.0
Análisis de ventas
def analizar_ventas(ventas):
"""
Analiza una lista de ventas y retorna estadísticas.
Args:
ventas: Lista de valores de ventas
Returns:
dict: Estadísticas calculadas
"""
if not ventas:
return None
total = sum(ventas)
promedio = total / len(ventas)
maximo = max(ventas)
minimo = min(ventas)
rango = maximo - minimo
# Calcular mediana
ventas_ordenadas = sorted(ventas)
n = len(ventas_ordenadas)
if n % 2 == 0:
mediana = (ventas_ordenadas[n//2 - 1] + ventas_ordenadas[n//2]) / 2
else:
mediana = ventas_ordenadas[n//2]
return {
"total": total,
"promedio": promedio,
"mediana": mediana,
"maximo": maximo,
"minimo": minimo,
"rango": rango,
"cantidad": len(ventas)
}
# Analizar ventas mensuales
ventas_mensuales = [45000, 52000, 48000, 61000, 55000, 70000]
stats = analizar_ventas(ventas_mensuales)
print("Estadísticas de ventas:")
print(f" Total: ${stats['total']:,}")
print(f" Promedio: ${stats['promedio']:,.2f}")
print(f" Mediana: ${stats['mediana']:,.2f}")
print(f" Máximo: ${stats['maximo']:,}")
print(f" Mínimo: ${stats['minimo']:,}")
print(f" Rango: ${stats['rango']:,}")
Parámetros avanzados
Parámetros con valores por defecto
def generar_reporte(titulo, datos, formato="pdf", incluir_graficos=True):
"""Genera un reporte con opciones configurables"""
print(f"Generando reporte: {titulo}")
print(f" Formato: {formato}")
print(f" Incluir gráficos: {incluir_graficos}")
print(f" Registros: {len(datos)}")
# Usar defaults
generar_reporte("Ventas Q1", [1,2,3])
# Sobrescribir algunos defaults
generar_reporte("Ventas Q1", [1,2,3], formato="excel")
# Usar argumentos nombrados (keywords)
generar_reporte("Ventas Q1", [1,2,3], incluir_graficos=False, formato="html")
*args: Número variable de argumentos
def calcular_promedio(*numeros):
"""Calcula el promedio de cualquier cantidad de números"""
if not numeros:
return 0
return sum(numeros) / len(numeros)
print(calcular_promedio(10, 20, 30)) # 20.0
print(calcular_promedio(100, 200, 300, 400)) # 250.0
print(calcular_promedio(5)) # 5.0
**kwargs: Argumentos nombrados variables
def crear_usuario(**datos):
"""Crea un usuario con cualquier cantidad de atributos"""
print("Creando usuario con los siguientes datos:")
for clave, valor in datos.items():
print(f" {clave}: {valor}")
crear_usuario(
nombre="María",
edad=28,
email="maria@empresa.com",
ciudad="Madrid",
rol="Analista"
)
Combinación de tipos de parámetros
def registrar_venta(producto_id, cantidad, precio, *extras, **metadata):
"""
Registra una venta con datos flexibles.
Args:
producto_id: ID del producto (posicional)
cantidad: Cantidad vendida (posicional)
precio: Precio unitario (posicional)
*extras: Datos adicionales como lista
**metadata: Datos adicionales como dict
"""
total = cantidad * precio
print(f"Venta registrada:")
print(f" Producto: {producto_id}")
print(f" Cantidad: {cantidad}")
print(f" Precio unitario: ${precio}")
print(f" Total: ${total}")
if extras:
print(f" Extras: {extras}")
if metadata:
print(f" Metadata:")
for key, value in metadata.items():
print(f" {key}: {value}")
registrar_venta(
"LAPTOP-001",
2,
800,
"Con garantía extendida",
"Envío express",
vendedor="Carlos",
sucursal="Madrid Centro",
promocion="Black Friday"
)
Lambda functions (funciones anónimas)
# Función normal
def cuadrado(x):
return x ** 2
# Lambda equivalente (función anónima)
cuadrado_lambda = lambda x: x ** 2
print(cuadrado(5)) # 25
print(cuadrado_lambda(5)) # 25
# Lambdas son útiles con funciones de orden superior
ventas = [1200, 1450, 1100, 1800, 1950]
# Filtrar ventas > 1400
ventas_altas = list(filter(lambda x: x > 1400, ventas))
print(ventas_altas) # [1450, 1800, 1950]
# Aplicar descuento del 10%
ventas_con_descuento = list(map(lambda x: x * 0.9, ventas))
print(ventas_con_descuento) # [1080.0, 1305.0, 990.0, 1620.0, 1755.0]
# Ordenar productos por precio
productos = [
{"nombre": "Laptop", "precio": 800},
{"nombre": "Mouse", "precio": 25},
{"nombre": "Teclado", "precio": 60}
]
productos_ordenados = sorted(productos, key=lambda p: p["precio"])
for p in productos_ordenados:
print(f"{p['nombre']}: ${p['precio']}")
Scope de variables
# Variable global
empresa = "Tooldata"
def funcion_con_variables():
# Variable local
empleados = 50
print(f"Empresa: {empresa}") # Accede a global
print(f"Empleados: {empleados}") # Accede a local
funcion_con_variables()
print(f"Empresa: {empresa}") # OK
# print(f"Empleados: {empleados}") # Error: empleados no existe aquí
# Modificar variable global (no recomendado)
contador = 0
def incrementar_contador():
global contador # Declarar que usamos la variable global
contador += 1
incrementar_contador()
print(contador) # 1
Módulos: Organizar código en archivos
Crear tu propio módulo
Crea un archivo analytics_tools.py:
# analytics_tools.py
"""
Módulo de herramientas para análisis de datos.
"""
def calcular_ctr(impresiones, clics):
"""Calcula el CTR (Click-Through Rate)"""
if impresiones == 0:
return 0
return (clics / impresiones) * 100
def calcular_roi(ingresos, inversion):
"""Calcula el ROI (Return on Investment)"""
if inversion == 0:
return 0
return ((ingresos - inversion) / inversion) * 100
def clasificar_cliente(valor_compras):
"""Clasifica clientes según valor de compras"""
if valor_compras >= 10000:
return "VIP"
elif valor_compras >= 5000:
return "Premium"
elif valor_compras >= 1000:
return "Regular"
else:
return "Nuevo"
# Constantes del módulo
IVA_ESTANDAR = 0.21
IVA_REDUCIDO = 0.10
Usar tu módulo
# En tu notebook o script principal
import analytics_tools
# Usar funciones del módulo
ctr = analytics_tools.calcular_ctr(100000, 3000)
print(f"CTR: {ctr}%")
roi = analytics_tools.calcular_roi(50000, 10000)
print(f"ROI: {roi}%")
categoria = analytics_tools.clasificar_cliente(7500)
print(f"Categoría: {categoria}")
# Acceder a constantes
precio = 100
precio_con_iva = precio * (1 + analytics_tools.IVA_ESTANDAR)
print(f"Precio con IVA: ${precio_con_iva}")
Diferentes formas de importar
# Importar todo el módulo
import analytics_tools
resultado = analytics_tools.calcular_ctr(1000, 30)
# Importar funciones específicas
from analytics_tools import calcular_ctr, calcular_roi
resultado = calcular_ctr(1000, 30) # No necesitas prefijo
# Importar todo (no recomendado)
from analytics_tools import *
resultado = calcular_ctr(1000, 30)
# Importar con alias
import analytics_tools as at
resultado = at.calcular_ctr(1000, 30)
# Importar función con alias
from analytics_tools import calcular_ctr as ctr
resultado = ctr(1000, 30)
Módulos incorporados útiles
math: Operaciones matemáticas
import math
# Funciones matemáticas
print(math.sqrt(16)) # 4.0 (raíz cuadrada)
print(math.ceil(4.3)) # 5 (redondear arriba)
print(math.floor(4.9)) # 4 (redondear abajo)
print(math.log(100, 10)) # 2.0 (logaritmo)
print(math.pi) # 3.141592...
# Cálculo de crecimiento exponencial
capital_inicial = 10000
tasa = 0.07
años = 5
capital_final = capital_inicial * math.exp(tasa * años)
print(f"Capital final: ${capital_final:,.2f}")
random: Números aleatorios
import random
# Número aleatorio entre 0 y 1
print(random.random())
# Número aleatorio en un rango
print(random.randint(1, 100))
# Elegir elemento aleatorio
productos = ["Laptop", "Mouse", "Teclado", "Monitor"]
print(random.choice(productos))
# Mezclar lista
random.shuffle(productos)
print(productos)
# Simular datos de prueba
ventas_simuladas = [random.randint(1000, 2000) for _ in range(7)]
print(f"Ventas simuladas: {ventas_simuladas}")
datetime: Manejo de fechas
from datetime import datetime, timedelta
# Fecha y hora actual
ahora = datetime.now()
print(f"Ahora: {ahora}")
print(f"Fecha: {ahora.date()}")
print(f"Hora: {ahora.time()}")
# Formatear fechas
print(ahora.strftime("%Y-%m-%d")) # 2024-10-26
print(ahora.strftime("%d/%m/%Y %H:%M")) # 26/10/2024 15:30
# Operaciones con fechas
ayer = ahora - timedelta(days=1)
proxima_semana = ahora + timedelta(weeks=1)
print(f"Ayer: {ayer.date()}")
print(f"Próxima semana: {proxima_semana.date()}")
# Calcular diferencia de días
fecha_inicio = datetime(2024, 1, 1)
dias_transcurridos = (ahora - fecha_inicio).days
print(f"Días transcurridos este año: {dias_transcurridos}")
Proyecto práctico: Sistema de análisis de ventas
# ventas_analyzer.py
"""Sistema completo de análisis de ventas"""
from datetime import datetime
def cargar_ventas():
"""Retorna datos de ejemplo de ventas"""
return [
{"fecha": "2024-01-15", "producto": "Laptop", "cantidad": 2, "precio": 800},
{"fecha": "2024-01-16", "producto": "Mouse", "cantidad": 5, "precio": 25},
{"fecha": "2024-01-16", "producto": "Teclado", "cantidad": 3, "precio": 60},
{"fecha": "2024-01-17", "producto": "Monitor", "cantidad": 1, "precio": 300},
{"fecha": "2024-01-18", "producto": "Laptop", "cantidad": 1, "precio": 800},
]
def calcular_total_venta(venta):
"""Calcula el total de una venta"""
return venta["cantidad"] * venta["precio"]
def analizar_por_producto(ventas):
"""Agrupa ventas por producto"""
productos = {}
for venta in ventas:
producto = venta["producto"]
total_venta = calcular_total_venta(venta)
if producto not in productos:
productos[producto] = {
"cantidad_total": 0,
"ingresos_total": 0,
"num_transacciones": 0
}
productos[producto]["cantidad_total"] += venta["cantidad"]
productos[producto]["ingresos_total"] += total_venta
productos[producto]["num_transacciones"] += 1
return productos
def generar_reporte(ventas):
"""Genera reporte completo de ventas"""
print("="*60)
print("REPORTE DE VENTAS")
print("="*60)
# Análisis general
total_ingresos = sum(calcular_total_venta(v) for v in ventas)
total_transacciones = len(ventas)
print(f"\nRESUMEN GENERAL:")
print(f" Total de transacciones: {total_transacciones}")
print(f" Ingresos totales: ${total_ingresos:,}")
print(f" Ticket promedio: ${total_ingresos / total_transacciones:,.2f}")
# Análisis por producto
print(f"\nANÁLISIS POR PRODUCTO:")
productos = analizar_por_producto(ventas)
for producto, stats in productos.items():
print(f"\n {producto}:")
print(f" Unidades vendidas: {stats['cantidad_total']}")
print(f" Ingresos: ${stats['ingresos_total']:,}")
print(f" Transacciones: {stats['num_transacciones']}")
promedio = stats['ingresos_total'] / stats['num_transacciones']
print(f" Venta promedio: ${promedio:,.2f}")
# Top producto
top_producto = max(productos.items(), key=lambda x: x[1]['ingresos_total'])
print(f"\n🏆 TOP PRODUCTO:")
print(f" {top_producto[0]} - ${top_producto[1]['ingresos_total']:,} en ingresos")
# Ejecutar análisis
if __name__ == "__main__":
ventas = cargar_ventas()
generar_reporte(ventas)
Buenas prácticas
1. Docstrings descriptivos
def calcular_descuento(precio, porcentaje, cliente_vip=False):
"""
Calcula el precio final con descuento aplicado.
Args:
precio (float): Precio original del producto
porcentaje (float): Porcentaje de descuento (0-100)
cliente_vip (bool): Si es cliente VIP (descuento adicional 5%)
Returns:
float: Precio final con descuento aplicado
Examples:
>>> calcular_descuento(100, 10)
90.0
>>> calcular_descuento(100, 10, cliente_vip=True)
85.5
"""
descuento = precio * (porcentaje / 100)
precio_con_descuento = precio - descuento
if cliente_vip:
descuento_vip = precio_con_descuento * 0.05
precio_con_descuento -= descuento_vip
return precio_con_descuento
2. Funciones pequeñas y enfocadas
❌ Mal: Función que hace demasiado
def procesar_todo(datos):
# 200 líneas de código haciendo muchas cosas...
pass
✅ Bien: Funciones específicas
def limpiar_datos(datos):
# Solo limpia datos
pass
def calcular_metricas(datos):
# Solo calcula métricas
pass
def generar_reporte(metricas):
# Solo genera reporte
pass
3. Validar inputs
def calcular_ctr(impresiones, clics):
"""Calcula CTR con validación"""
# Validar tipos
if not isinstance(impresiones, (int, float)) or not isinstance(clics, (int, float)):
raise TypeError("Impresiones y clics deben ser números")
# Validar valores
if impresiones < 0 or clics < 0:
raise ValueError("Los valores no pueden ser negativos")
if clics > impresiones:
raise ValueError("Los clics no pueden superar las impresiones")
if impresiones == 0:
return 0
return (clics / impresiones) * 100
Resumen de la lección
✅ Las funciones permiten reutilizar código y mantenerlo organizado ✅ Usa parámetros para hacer funciones flexibles y return para devolver valores ✅ Docstrings documentan qué hace cada función ✅ Lambda functions son útiles para operaciones simples de una línea ✅ Los módulos organizan funciones relacionadas en archivos separados ✅ Python tiene módulos incorporados poderosos (math, random, datetime)
🎯 Próxima lección: 06. Introducción a Pandas
¡Felicidades! Completaste el Módulo 1. En el siguiente módulo comenzarás con Pandas, la librería más importante para análisis de datos. 🚀
¿Completaste esta lección?
Marca esta lección como completada. Tu progreso se guardará en tu navegador.