*args y **kwargs permiten crear funciones Python que aceptan una cantidad flexible de argumentos. Son útiles en bibliotecas, decoradores, constructores y funciones que reenvían parámetros. Aunque los nombres “args” y “kwargs” son convencionales, lo realmente importante son uno y dos asteriscos.
Parámetros normales y flexibles
Una función con parámetros normales exige una cantidad concreta de valores. Con *args, los argumentos posicionales adicionales se agrupan en una tupla. Con **kwargs, los argumentos nombrados adicionales se agrupan en un diccionario. Para revisar la base, consulta esta guía de funciones en Python.
def mostrar_datos(nombre, *args, **kwargs):
print("Nombre:", nombre)
print("Posicionales:", args)
print("Nombrados:", kwargs)
mostrar_datos(
"Lucía",
10,
20,
ciudad="Madrid",
activo=True
)Cómo funciona *args
*args captura valores posicionales restantes y permite iterarlos:
def sumar(*numeros):
total = 0
for numero in numeros:
total += numero
return total
print(sumar(2, 4, 6))
print(sumar(10, 20, 30, 40))La función puede recibir cero, uno o muchos valores. Sin embargo, flexibilidad no significa ausencia de validación. Si solo deberían aceptarse números, conviene comprobar los datos o documentar el contrato de la función.
Cómo funciona **kwargs
**kwargs captura argumentos con nombre:
def crear_perfil(**datos):
for clave, valor in datos.items():
print(f"{clave}: {valor}")
crear_perfil(
nombre="Carlos",
profesion="Desarrollador",
remoto=True
)Este patrón es útil para opciones configurables. Aun así, cuando la estructura es estable, parámetros explícitos o modelos tipados suelen ser más claros.
Orden correcto de los parámetros
Una firma puede combinar parámetros posicionales, valores predeterminados, *args, parámetros solo por nombre y **kwargs. El orden importa:
def ejemplo(obligatorio, *args, opcion=False, **kwargs):
passDespués de *args, los parámetros se proporcionan por nombre. Esta característica ayuda a crear APIs más legibles y evita confusiones.
Desempaquetado al llamar funciones
Los asteriscos también sirven para desempaquetar colecciones:
def area(ancho, alto):
return ancho * alto
medidas = (8, 5)
print(area(*medidas))
configuracion = {"ancho": 10, "alto": 3}
print(area(**configuracion))La tupla aporta valores posicionales y el diccionario aporta valores por nombre. Las claves del diccionario deben coincidir con los nombres de parámetros. El PEP 448 describe generalizaciones del desempaquetado en Python.
Reenviar argumentos
Uno de los usos más importantes consiste en recibir argumentos y pasarlos a otra función. Esto aparece en adaptadores, herencia y decoradores:
def registrar_llamada(funcion):
def wrapper(*args, **kwargs):
print("Ejecutando función")
return funcion(*args, **kwargs)
return wrapperLa guía de decoradores en Python profundiza en este patrón y explica por qué conviene utilizar functools.wraps.
Errores comunes
Un error frecuente es usar *args y **kwargs sin necesidad. Las firmas demasiado abiertas dificultan la documentación y esconden errores de escritura. Otro problema es suponer que args es una lista; en realidad es una tupla. kwargs sí es un diccionario.
También se confunde el acto de devolver un resultado con imprimirlo. Cuando una función calcula algo, normalmente debe usar return. La guía sobre la sentencia return explica cómo reutilizar resultados y evitar valores None inesperados.
Type hints para argumentos flexibles
Los argumentos flexibles pueden anotarse:
def promedio(*valores: float) -> float:
if not valores:
raise ValueError("Se requiere al menos un valor")
return sum(valores) / len(valores)Para estructuras más complejas, los type hints en Python ayudan a editores y analizadores estáticos. No sustituyen la validación en tiempo de ejecución, pero mejoran claridad y mantenimiento.
Cuándo utilizarlos
Usa *args cuando la función acepte una secuencia variable de valores homogéneos. Usa **kwargs para opciones nombradas realmente abiertas o para reenviar configuración. Prefiere parámetros explícitos cuando conozcas la estructura y quieras que la interfaz sea fácil de descubrir.
La documentación oficial sobre definición de funciones explica argumentos posicionales, nombrados, especiales y listas de parámetros. Con práctica, los asteriscos dejan de parecer una sintaxis misteriosa y se convierten en una herramienta precisa para diseñar funciones flexibles.
Parámetros solo posicionales y solo por nombre
Python permite controlar aún más la interfaz con los símbolos / y *. Los parámetros antes de / solo pueden pasarse por posición. Los parámetros después de un asterisco deben enviarse por nombre. Esta sintaxis es útil en APIs públicas porque evita ambigüedades y permite cambiar nombres internos sin romper llamadas posicionales.
def conectar(host, /, puerto=5432, *, seguro=True):
return host, puerto, seguro
conectar("localhost", 5432, seguro=False)No es necesario utilizar todas estas posibilidades en funciones sencillas. Su valor aparece cuando la claridad de la interfaz importa más que la máxima flexibilidad.
Diseñar una API estable
Antes de añadir **kwargs, pregúntate si conoces las opciones válidas. Si son cinco opciones estables, parámetros nombrados explícitos ofrecen mejor autocompletado y detectan errores de escritura. Si estás creando un adaptador que reenvía opciones a otra biblioteca, **kwargs puede ser correcto. Documenta qué claves se aceptan y evita ignorar silenciosamente claves desconocidas.
Pruebas de funciones flexibles
Prueba llamadas sin argumentos adicionales, con varios posicionales, con opciones nombradas y con entradas inválidas. También comprueba colisiones: al desempaquetar un diccionario, no puedes proporcionar dos veces el mismo parámetro. Una interfaz flexible necesita pruebas más amplias porque existen más combinaciones posibles.






