Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Usa la rueda del ratón o gestos táctiles para hacer zoom • Arrastra para mover

Crear funciones con def

🧭 Navegación:

¡Bienvenido al taller de creación de herramientas de nuestro almacén! Las funciones son como máquinas especializadas que podemos diseñar y construir para automatizar tareas específicas. Una vez que aprendas a crearlas, tu eficiencia como “gerente del almacén” se multiplicará exponencialmente.

🏭 ¿Qué es una función?

Imagina que en tu almacén tienes que calcular el precio final de productos con descuentos e impuestos todo el tiempo. En lugar de hacer estos cálculos manualmente cada vez, puedes construir una máquina calculadora de precios que:

  • Reciba el precio original como entrada
  • Procese los cálculos internamente
  • Entregue el precio final como resultado

Esa máquina es una función en programación.

# Antes: Cálculos repetitivos y propensos a errores
precio_laptop = 1500
precio_laptop_con_descuento = precio_laptop * 0.90  # 10% descuento
precio_laptop_final = precio_laptop_con_descuento * 1.16  # 16% impuesto

precio_mouse = 35
precio_mouse_con_descuento = precio_mouse * 0.90
precio_mouse_final = precio_mouse_con_descuento * 1.16

precio_teclado = 120
precio_teclado_con_descuento = precio_teclado * 0.90
precio_teclado_final = precio_teclado_con_descuento * 1.16

# Después: Una función reutilizable
def calcular_precio_final(precio_original):
    """Máquina calculadora de precios del almacén"""
    precio_con_descuento = precio_original * 0.90
    precio_final = precio_con_descuento * 1.16
    return precio_final

# Uso simple y confiable
precio_laptop_final = calcular_precio_final(1500)
precio_mouse_final = calcular_precio_final(35)
precio_teclado_final = calcular_precio_final(120)

🔧 Anatomía de una función

La palabra clave def

Como en nuestro almacén necesitamos definir las especificaciones de cada máquina antes de construirla, en Python usamos def para definir una función:

def nombre_de_la_funcion():
    """Documentación de lo que hace la máquina"""
    # Código que ejecuta la máquina
    pass

Partes esenciales de una función

def procesar_pedido(codigo_producto, cantidad):
    """
    Procesa un pedido en el almacén.
    
    Args:
        codigo_producto (str): Código único del producto
        cantidad (int): Cantidad solicitada
    
    Returns:
        dict: Información del pedido procesado
    """
    # 1. Validar que el producto existe
    if not codigo_producto.startswith("PROD"):
        return {"error": "Código de producto inválido"}
    
    # 2. Verificar stock disponible
    stock_actual = consultar_stock(codigo_producto)
    if stock_actual < cantidad:
        return {"error": "Stock insuficiente"}
    
    # 3. Procesar el pedido
    precio_unitario = obtener_precio(codigo_producto)
    total = precio_unitario * cantidad
    
    # 4. Retornar el resultado
    return {
        "codigo": codigo_producto,
        "cantidad": cantidad,
        "total": total,
        "status": "procesado"
    }

Análisis de las partes:

  1. def - Palabra clave para definir la función
  2. procesar_pedido - Nombre descriptivo de la función
  3. (codigo_producto, cantidad) - Parámetros de entrada
  4. """docstring""" - Documentación de la función
  5. Cuerpo de la función - El código que se ejecuta
  6. return - Valor que devuelve la función

🏗️ Creando tu primera función

Función básica sin parámetros

def saludar_empleados():
    """Función que saluda a los empleados del almacén"""
    print("¡Buenos días, equipo del almacén!")
    print("¡Listos para un día productivo!")

# Llamar (usar) la función
saludar_empleados()

Salida:

¡Buenos días, equipo del almacén!
¡Listos para un día productivo!

Función con un parámetro

def calcular_area_zona(longitud):
    """Calcula el área de una zona cuadrada del almacén"""
    area = longitud ** 2
    print(f"El área de la zona es: {area} metros cuadrados")

# Usar la función
calcular_area_zona(10)  # Área de 100 m²
calcular_area_zona(25)  # Área de 625 m²

Función con múltiples parámetros

def generar_etiqueta_producto(nombre, precio, categoria, en_oferta=False):
    """Genera una etiqueta de precio para un producto"""
    etiqueta = f"🏷️ {nombre}\n"
    etiqueta += f"💰 Precio: ${precio:.2f}\n"
    etiqueta += f"📂 Categoría: {categoria}\n"
    
    if en_oferta:
        etiqueta += "🔥 ¡EN OFERTA!"
    
    print(etiqueta)

# Ejemplos de uso
generar_etiqueta_producto("Laptop Gaming", 1500.00, "Electrónicos")
generar_etiqueta_producto("Mouse Inalámbrico", 35.99, "Accesorios", True)

📊 Funciones que retornan valores

Diferencia entre print y return

# Función que IMPRIME (no retorna)
def mostrar_descuento(precio, porcentaje):
    """Muestra el descuento pero no retorna nada útil"""
    descuento = precio * (porcentaje / 100)
    print(f"Descuento: ${descuento:.2f}")
    # No tiene return, por lo que retorna None implícitamente

# Función que RETORNA (más útil)
def calcular_descuento(precio, porcentaje):
    """Calcula y retorna el valor del descuento"""
    descuento = precio * (porcentaje / 100)
    return descuento

# Comparación de uso
mostrar_descuento(100, 15)  # Imprime: Descuento: $15.00
resultado = mostrar_descuento(100, 15)  # resultado = None (no útil)

descuento = calcular_descuento(100, 15)  # descuento = 15.0 (útil!)
precio_final = 100 - descuento  # Podemos usar el resultado
print(f"Precio final: ${precio_final:.2f}")

Función calculadora completa del almacén

def calcular_metricas_venta(precio_base, cantidad, descuento_porcentaje=0, impuesto_porcentaje=16):
    """
    Calculadora completa de métricas de venta del almacén.
    
    Args:
        precio_base (float): Precio unitario del producto
        cantidad (int): Cantidad de productos vendidos
        descuento_porcentaje (float): Porcentaje de descuento (0-100)
        impuesto_porcentaje (float): Porcentaje de impuesto (0-100)
    
    Returns:
        dict: Diccionario con todas las métricas calculadas
    """
    # Cálculos paso a paso
    subtotal = precio_base * cantidad
    descuento = subtotal * (descuento_porcentaje / 100)
    subtotal_con_descuento = subtotal - descuento
    impuesto = subtotal_con_descuento * (impuesto_porcentaje / 100)
    total_final = subtotal_con_descuento + impuesto
    
    # Retornar todas las métricas
    return {
        "subtotal": subtotal,
        "descuento": descuento,
        "subtotal_con_descuento": subtotal_con_descuento,
        "impuesto": impuesto,
        "total_final": total_final,
        "ahorro_cliente": descuento
    }

# Ejemplo de uso
venta = calcular_metricas_venta(precio_base=50, cantidad=3, descuento_porcentaje=10)

print(f"📊 RESUMEN DE VENTA")
print(f"Subtotal: ${venta['subtotal']:.2f}")
print(f"Descuento: ${venta['descuento']:.2f}")
print(f"Impuesto: ${venta['impuesto']:.2f}")
print(f"Total: ${venta['total_final']:.2f}")
print(f"Ahorro del cliente: ${venta['ahorro_cliente']:.2f}")

🎨 Mejores prácticas para crear funciones

1. Nombres descriptivos y claros

# ❌ Nombres poco descriptivos
def calc(x, y):
    return x * y * 0.16

def proc(data):
    # ¿Qué procesa? ¿Cómo?
    pass

# ✅ Nombres descriptivos
def calcular_impuesto_venta(precio_base, cantidad):
    """Calcula el impuesto de una venta basado en precio y cantidad"""
    return precio_base * cantidad * 0.16

def procesar_devolucion_producto(producto_info):
    """Procesa la devolución de un producto al inventario"""
    pass

2. Funciones pequeñas con una responsabilidad

# ❌ Función que hace demasiadas cosas
def procesar_pedido_completo(codigo, cantidad, cliente):
    # Validar producto
    # Verificar stock
    # Calcular precios
    # Procesar pago
    # Actualizar inventario
    # Enviar email
    # Generar factura
    # Actualizar estadísticas
    pass  # ¡Demasiadas responsabilidades!

# ✅ Funciones especializadas
def validar_producto(codigo):
    """Se enfoca solo en validar si un producto es válido"""
    return codigo.startswith("PROD") and len(codigo) == 8

def verificar_stock_disponible(codigo, cantidad_solicitada):
    """Se enfoca solo en verificar stock"""
    stock_actual = obtener_stock(codigo)
    return stock_actual >= cantidad_solicitada

def calcular_precio_total(codigo, cantidad):
    """Se enfoca solo en calcular precios"""
    precio_unitario = obtener_precio(codigo)
    return precio_unitario * cantidad

3. Documentación clara con docstrings

def gestionar_inventario_automatico(productos, umbral_minimo=10):
    """
    Gestiona automáticamente el inventario basado en umbrales mínimos.
    
    Esta función revisa todos los productos en el inventario y genera
    órdenes de recompra automáticas para aquellos productos cuyo stock
    está por debajo del umbral especificado.
    
    Args:
        productos (list): Lista de diccionarios con información de productos.
                         Cada producto debe tener las claves: 'codigo', 'nombre', 'stock'
        umbral_minimo (int, opcional): Stock mínimo antes de generar reorden.
                                      Por defecto es 10.
    
    Returns:
        dict: Resultado del procesamiento con las siguientes claves:
            - 'productos_procesados': Número total de productos revisados
            - 'reordenes_generadas': Número de órdenes de recompra creadas
            - 'productos_criticos': Lista de productos con stock crítico
    
    Raises:
        ValueError: Si la lista de productos está vacía o mal formateada
        TypeError: Si umbral_minimo no es un número entero
    
    Example:
        >>> productos = [
        ...     {'codigo': 'PROD001', 'nombre': 'Laptop', 'stock': 5},
        ...     {'codigo': 'PROD002', 'nombre': 'Mouse', 'stock': 15}
        ... ]
        >>> resultado = gestionar_inventario_automatico(productos, 8)
        >>> print(resultado['reordenes_generadas'])
        1
    """
    # Implementación de la función...
    pass

🔄 Funciones recursivas: Máquinas que se llaman a sí mismas

Algunas máquinas en nuestro almacén necesitan usar versiones más pequeñas de sí mismas. Por ejemplo, una máquina que cuenta todos los elementos en cajas que pueden contener otras cajas:

def contar_elementos_totales(contenedor):
    """
    Cuenta todos los elementos en un contenedor que puede tener sub-contenedores.
    
    Args:
        contenedor (list): Lista que puede contener números o otras listas
    
    Returns:
        int: Número total de elementos contados
    """
    total = 0
    
    for elemento in contenedor:
        if isinstance(elemento, list):  # Si es una sub-caja
            # La máquina se llama a sí misma para contar la sub-caja
            total += contar_elementos_totales(elemento)
        else:  # Si es un elemento individual
            total += 1
    
    return total

# Ejemplo de almacén con estructura anidada
almacen_principal = [
    "producto1",
    "producto2", 
    ["sub_caja1", "sub_caja2", ["caja_pequena1", "caja_pequena2"]],
    "producto3",
    ["otra_subcaja"]
]

total_productos = contar_elementos_totales(almacen_principal)
print(f"Total de productos en el almacén: {total_productos}")
# Resultado: 7 productos

🚀 Funciones lambda: Máquinas portátiles

Para tareas muy simples, Python permite crear mini-máquinas portátiles llamadas funciones lambda:

# Función tradicional
def aplicar_descuento_standard(precio):
    return precio * 0.90

# Función lambda equivalente (para casos simples)
aplicar_descuento = lambda precio: precio * 0.90

# Uso práctico con listas de productos
precios = [100, 250, 75, 400, 150]

# Aplicar descuento a todos los precios
precios_con_descuento = list(map(lambda precio: precio * 0.90, precios))
print(f"Precios originales: {precios}")
print(f"Precios con descuento: {precios_con_descuento}")

# Filtrar productos caros (más de $200)
productos_premium = list(filter(lambda precio: precio > 200, precios))
print(f"Productos premium: {productos_premium}")

🏭 Proyecto práctico: Sistema de gestión de productos

Vamos a crear un sistema completo con múltiples funciones especializadas:

# Base de datos simulada de productos
productos_almacen = [
    {"codigo": "LAP001", "nombre": "Laptop Gaming", "precio": 1500, "stock": 5, "categoria": "Electronica"},
    {"codigo": "MOU001", "nombre": "Mouse Inalámbrico", "precio": 35, "stock": 20, "categoria": "Accesorios"},
    {"codigo": "TEC001", "nombre": "Teclado Mecánico", "precio": 120, "stock": 8, "categoria": "Accesorios"},
    {"codigo": "MON001", "nombre": "Monitor 4K", "precio": 350, "stock": 3, "categoria": "Electronica"}
]

def buscar_producto_por_codigo(codigo):
    """Busca un producto específico por su código"""
    for producto in productos_almacen:
        if producto["codigo"] == codigo:
            return producto
    return None

def calcular_valor_total_categoria(categoria):
    """Calcula el valor total de inventario de una categoría"""
    valor_total = 0
    for producto in productos_almacen:
        if producto["categoria"] == categoria:
            valor_total += producto["precio"] * producto["stock"]
    return valor_total

def generar_reporte_stock_bajo(umbral=10):
    """Genera reporte de productos con stock bajo"""
    productos_criticos = []
    for producto in productos_almacen:
        if producto["stock"] <= umbral:
            productos_criticos.append({
                "codigo": producto["codigo"],
                "nombre": producto["nombre"],
                "stock_actual": producto["stock"],
                "urgencia": "CRÍTICO" if producto["stock"] <= 5 else "BAJO"
            })
    return productos_criticos

def procesar_venta(codigo_producto, cantidad):
    """Procesa una venta y actualiza el inventario"""
    producto = buscar_producto_por_codigo(codigo_producto)
    
    if not producto:
        return {"error": "Producto no encontrado"}
    
    if producto["stock"] < cantidad:
        return {"error": f"Stock insuficiente. Disponible: {producto['stock']}"}
    
    # Actualizar stock
    producto["stock"] -= cantidad
    total_venta = producto["precio"] * cantidad
    
    return {
        "venta_exitosa": True,
        "producto": producto["nombre"],
        "cantidad_vendida": cantidad,
        "total": total_venta,
        "stock_restante": producto["stock"]
    }

# Ejemplo de uso del sistema
print("=== SISTEMA DE GESTIÓN DE ALMACÉN ===")

# Buscar un producto
laptop = buscar_producto_por_codigo("LAP001")
print(f"Producto encontrado: {laptop['nombre']} - ${laptop['precio']}")

# Calcular valor por categoría
valor_electronica = calcular_valor_total_categoria("Electronica")
print(f"Valor total en Electrónica: ${valor_electronica}")

# Generar reporte de stock
productos_criticos = generar_reporte_stock_bajo(umbral=8)
print(f"Productos con stock crítico:")
for producto in productos_criticos:
    print(f"  - {producto['nombre']}: {producto['stock_actual']} unidades ({producto['urgencia']})")

# Procesar una venta
resultado_venta = procesar_venta("LAP001", 2)
if resultado_venta.get("venta_exitosa"):
    print(f"Venta procesada: {resultado_venta['cantidad_vendida']} x {resultado_venta['producto']}")
    print(f"Total: ${resultado_venta['total']}")
    print(f"Stock restante: {resultado_venta['stock_restante']}")

🎯 Comprueba tu comprensión

Ejercicio 1: Función básica

Crea una función llamada calcular_capacidad_estante que reciba la altura, ancho y profundidad de un estante y retorne su volumen en metros cúbicos.

def calcular_capacidad_estante(altura, ancho, profundidad):
    # Tu código aquí
    pass

# Prueba tu función
volumen = calcular_capacidad_estante(2.5, 1.2, 0.8)
print(f"Capacidad del estante: {volumen} m³")

Ejercicio 2: Función con validación

Crea una función llamada validar_codigo_producto que reciba un código de producto y verifique que:

  • Tenga exactamente 6 caracteres
  • Los primeros 3 sean letras mayúsculas
  • Los últimos 3 sean números
def validar_codigo_producto(codigo):
    # Tu código aquí
    pass

# Pruebas
print(validar_codigo_producto("LAP001"))  # Debería ser True
print(validar_codigo_producto("lap001"))  # Debería ser False
print(validar_codigo_producto("LAPTOP1")) # Debería ser False

Ejercicio 3: Función de procesamiento

Crea una función llamada procesar_lista_precios que reciba una lista de precios y un porcentaje de descuento, y retorne una nueva lista con los precios con descuento aplicado.

def procesar_lista_precios(precios, descuento_porcentaje):
    # Tu código aquí
    pass

# Prueba
precios_originales = [100, 250, 75, 400]
precios_rebajados = procesar_lista_precios(precios_originales, 15)
print(f"Precios rebajados: {precios_rebajados}")

💡 Consejos para el éxito

  1. Piensa en funciones como herramientas: Cada función debe tener un propósito específico y claro
  2. Reutilización es clave: Si escribes el mismo código más de 2 veces, crea una función
  3. Nombres descriptivos: El nombre debe explicar qué hace la función sin necesidad de leer el código
  4. Documenta siempre: Usa docstrings para explicar propósito, parámetros y valor de retorno
  5. Funciones pequeñas: Es mejor tener muchas funciones pequeñas que pocas funciones grandes
  6. Prueba tu código: Siempre verifica que tus funciones funcionen con diferentes valores de entrada

🎉 ¡Felicitaciones!

Has aprendido a crear máquinas especializadas (funciones) para tu almacén digital. Estas herramientas te permitirán:

  • ✅ Automatizar tareas repetitivas
  • ✅ Organizar mejor tu código
  • ✅ Reducir errores y bugs
  • ✅ Hacer tu código más legible y mantenible
  • ✅ Crear soluciones escalables

En la siguiente sección aprenderemos sobre parámetros y argumentos: cómo hacer que nuestras máquinas sean más flexibles y potentes.


🧭 Navegación: