Argumentos *args y **kwargs para Principiantes

Analogía: La Caja Mágica de Herramientas 🧰

Imagina que tienes una caja mágica de herramientas:

  • *args es como un compartimento para herramientas sueltas (sin etiquetas)

  • **kwargs es como un compartimento para herramientas etiquetadas (cada una con su nombre)

Ambos te permiten recibir cantidades variables de cosas sin saber exactamente cuántas vendrán.


¿Qué son *args y **kwargs?

Son parámetros especiales que permiten a una función aceptar:

  • *args: Número variable de argumentos posicionales

  • **kwargs: Número variable de argumentos con nombre (keyword arguments)


*args (Argumentos Posicionales Variables)

Ejemplo 1: Sumar Cantidad Variable de Números ➕

python
def sumar_numeros(*args):
    """
    *args recibe CUALQUIER cantidad de números
    y los guarda en una TUPLA
    """
    print(f"args es una tupla: {args}")
    print(f"Tipo de args: {type(args)}")
    
    total = 0
    for numero in args:
        total += numero
    
    return total

print("=== SUMA CON *args ===")
print(sumar_numeros(1, 2))           # 2 números
print(sumar_numeros(1, 2, 3, 4))     # 4 números  
print(sumar_numeros(5, 10, 15, 20, 25))  # 5 números

Output:

text
=== SUMA CON *args ===
args es una tupla: (1, 2)
Tipo de args: <class 'tuple'>
3
args es una tupla: (1, 2, 3, 4)
Tipo de args: <class 'tuple'>
10
args es una tupla: (5, 10, 15, 20, 25)
Tipo de args: <class 'tuple'>
75

¿Qué pasa detrás?

python
# Cuando llamas: sumar_numeros(1, 2, 3)
# Python hace: args = (1, 2, 3)

Ejemplo 2: Crear Lista de Compras 🛒

python
def lista_compras(producto_principal, *otros_productos):
    print(f"🛒 Producto principal: {producto_principal}")
    print(f"📝 Otros productos: {otros_productos}")
    
    lista_final = [producto_principal]
    for producto in otros_productos:
        lista_final.append(producto)
    
    return lista_final

print("=== LISTA DE COMPRAS ===")
compra1 = lista_compras("Leche", "Pan", "Huevos", "Queso")
print(f"Lista final: {compra1}")

print("\n" + "="*30)
compra2 = lista_compras("Arroz")  # Solo un producto
print(f"Lista final: {compra2}")

Output:

text
=== LISTA DE COMPRAS ===
🛒 Producto principal: Leche
📝 Otros productos: ('Pan', 'Huevos', 'Queso')
Lista final: ['Leche', 'Pan', 'Huevos', 'Queso']

==============================
🛒 Producto principal: Arroz
📝 Otros productos: ()
Lista final: ['Arroz']

**kwargs (Argumentos con Nombre Variables)

Ejemplo 3: Crear Perfil de Usuario 👤

python
def crear_perfil(**kwargs):
    """
    **kwargs recibe CUALQUIER cantidad de argumentos con nombre
    y los guarda en un DICCIONARIO
    """
    print(f"kwargs es un diccionario: {kwargs}")
    print(f"Tipo de kwargs: {type(kwargs)}")
    
    print("\n📋 PERFIL CREADO:")
    for clave, valor in kwargs.items():
        print(f"  {clave}: {valor}")
    
    return kwargs

print("=== PERFILES CON **kwargs ===")
perfil1 = crear_perfil(nombre="Ana", edad=25, ciudad="Madrid")
print("\n" + "="*30)
perfil2 = crear_perfil(nombre="Carlos", profesion="Programador", email="carlos@email.com", activo=True)

Output:

text
=== PERFILES CON **kwargs ===
kwargs es un diccionario: {'nombre': 'Ana', 'edad': 25, 'ciudad': 'Madrid'}
Tipo de kwargs: <class 'dict'>

📋 PERFIL CREADO:
  nombre: Ana
  edad: 25
  ciudad: Madrid

==============================
kwargs es un diccionario: {'nombre': 'Carlos', 'profesion': 'Programador', 'email': 'carlos@email.com', 'activo': True}
Tipo de kwargs: <class 'dict'>

📋 PERFIL CREADO:
  nombre: Carlos
  profesion: Programador
  email: carlos@email.com
  activo: True

¿Qué pasa detrás?

python
# Cuando llamas: crear_perfil(nombre="Ana", edad=25)
# Python hace: kwargs = {'nombre': 'Ana', 'edad': 25}

Ejemplo 4: Configurar un Juego 🎮

python
def configurar_juego(nombre, **configuraciones):
    print(f"🎮 Juego: {nombre}")
    print("⚙️ Configuraciones:")
    
    # Valores por defecto
    config_default = {
        'dificultad': 'normal',
        'sonido': True,
        'graficos': 'medios'
    }
    
    # Actualizar con las configuraciones proporcionadas
    config_default.update(configuraciones)
    
    for clave, valor in config_default.items():
        print(f"  {clave}: {valor}")
    
    return config_default

print("=== CONFIGURACIÓN DE JUEGO ===")
config1 = configurar_juego("Super Aventura")
print("\n" + "="*40)
config2 = configurar_juego(
    "Misión Espacial", 
    dificultad="difícil", 
    graficos="altos",
    jugadores=2
)

Output:

text
=== CONFIGURACIÓN DE JUEGO ===
🎮 Juego: Super Aventura
⚙️ Configuraciones:
  dificultad: normal
  sonido: True
  graficos: medios

========================================
🎮 Juego: Misión Espacial
⚙️ Configuraciones:
  dificultad: difícil
  sonido: True
  graficos: altos
  jugadores: 2

Usando *args y **kwargs Juntos

Ejemplo 5: Función Universal de Información 🌟

python
def mostrar_info(*args, **kwargs):
    print("📊 INFORMACIÓN RECIBIDA:")
    
    if args:
        print("\n📦 Argumentos posicionales (*args):")
        for i, arg in enumerate(args):
            print(f"  Argumento {i+1}: {arg}")
    
    if kwargs:
        print("\n🏷️ Argumentos con nombre (**kwargs):")
        for clave, valor in kwargs.items():
            print(f"  {clave}: {valor}")

print("=== USANDO AMBOS ===")
mostrar_info("Python", "es", "genial", lenguaje="Python", nivel="principiante", año=2024)

Output:

text
=== USANDO AMBOS ===
📊 INFORMACIÓN RECIBIDA:

📦 Argumentos posicionales (*args):
  Argumento 1: Python
  Argumento 2: es
  Argumento 3: genial

🏷️ Argumentos con nombre (**kwargs):
  lenguaje: Python
  nivel: principiante
  año: 2024

Ejemplo 6: Decorador con *args y **kwargs 🎨

python
def decorador_universal(funcion_original):
    def wrapper(*args, **kwargs):
        print(f"🎯 Función '{funcion_original.__name__}' llamada")
        print(f"📦 args: {args}")
        print(f"🏷️ kwargs: {kwargs}")
        
        resultado = funcion_original(*args, **kwargs)
        
        print(f"✅ Resultado: {resultado}")
        return resultado
    return wrapper

@decorador_universal
def saludar_personal(nombre, saludo="Hola", veces=1):
    return f"{saludo} {nombre}! " * veces

print("=== DECORADOR UNIVERSAL ===")
saludar_personal("Ana")
print("\n" + "="*30)
saludar_personal("Carlos", saludo="Buenos días", veces=2)

Output:

text
=== DECORADOR UNIVERSAL ===
🎯 Función 'saludar_personal' llamada
📦 args: ('Ana',)
🏷️ kwargs: {}
✅ Resultado: Hola Ana! 

==============================
🎯 Función 'saludar_personal' llamada
📦 args: ('Carlos',)
🏷️ kwargs: {'saludo': 'Buenos días', 'veces': 2}
✅ Resultado: Buenos días Carlos! Buenos días Carlos! 

Reglas de Orden IMPORTANTES 🚦

python
def funcion_correcta(parametro_normal, *args, **kwargs):
    # 1. Parámetros normales
    # 2. *args
    # 3. **kwargs
    pass

# ✅ CORRECTO
funcion_correcta("normal", "arg1", "arg2", clave1="valor1", clave2="valor2")

# ❌ INCORRECTO - Este orden no funciona
# def funcion_incorrecta(**kwargs, *args, parametro_normal):

Resumen Visual

text
*args   = (valor1, valor2, valor3)     → TUPLA
**kwargs = {clave1: valor1, clave2: valor2} → DICCIONARIO

Diferencias Clave:

Característica*args**kwargs
TipoTuplaDiccionario
UsoArgumentos posicionalesArgumentos con nombre
Sintaxis llamadafunc(1, 2, 3)func(a=1, b=2)
AccesoPor índice: args[0]Por clave: kwargs['clave']

Casos de Uso Comunes:

  1. *args: Cuando no sabes cuántos argumentos recibirás

  2. **kwargs: Para configuraciones flexibles

  3. Decoradores: Para trabajar con cualquier función

  4. Herencia: Pasar argumentos a funciones padre

Puntos Clave para Principiantes:

  1. *args recoge argumentos extra posicionales en una tupla

  2. **kwargs recoge argumentos extra con nombre en un diccionario

  3. El orden siempre es: (normal, *args, **kwargs)

  4. Los nombres args y kwargs son convenciones, puedes usar otros

Comentarios

Entradas populares de este blog

¿Qué es un Closure?

Calculadora de edad

Funciones en Python: con y sin paréntesis