Cuando no sabes cuántos argumentos va a haber
La mayoría de las funciones toman un número fijo de parámetros. Pero a veces necesitas algo más flexible — un logger que acepte cualquier número de mensajes, una función envoltorio que reenvíe lo que reciba a otra función, una función de dibujado que acepte configuración sin saber exactamente qué opciones usará quien la llame.
Python resuelve esto con dos marcadores especiales en la lista de parámetros: *args y **kwargs.
*args recoge argumentos posicionales
Un solo asterisco dice "empaqueta cualquier argumento posicional adicional en una tupla":
Dentro de la función, args es una tupla normal. Puedes iterar sobre ella, indexarla, pasarla a len() o hacer slicing.
*args suele aparecer junto a parámetros con nombre:
first captura el primer argumento; *rest empaqueta todo lo demás en una tupla.
**kwargs recoge argumentos de palabra clave
Dos asteriscos hacen lo equivalente para argumentos de palabra clave, empaquetándolos en un dict:
Dentro de describe, kwargs es un dict normal. Las claves son los nombres de las palabras clave como cadenas.
Usarlos juntos
Puedes usar ambos en la misma función. La convención es *args antes de **kwargs:
El orden completo de los parámetros, desde el principio al final, es:
- Parámetros posicionales normales (obligatorios o con valores por defecto).
*args.- Parámetros solo por palabra clave (todo lo que venga después de
*argsdebe pasarse por nombre). **kwargs.
title captura el primer argumento posicional. El resto de los posicionales van a tags. draft tiene que pasarse por palabra clave (viene después de *tags). Cualquier otro argumento por palabra clave aterriza en metadata.
Desempaquetar con * y ** en el sitio de la llamada
Los asteriscos también funcionan en sentido inverso — expandiendo una secuencia o dict hacia los argumentos de una llamada:
Esto resulta increíblemente útil para reenviar argumentos:
wrapped no necesita saber qué argumentos espera log. Simplemente recoge todo y lo reenvía. Este patrón aparece constantemente en decoradores (un tema más avanzado) y en funciones envoltorio.
Cuando *args y **kwargs son la elección equivocada
Es fácil emocionarse de más y usarlos en todas partes. Dos advertencias:
Ocultan lo que una función espera
Si cada función en tu código es def f(*args, **kwargs), quien llama no tiene idea de qué argumentos son válidos. Usa parámetros con nombre siempre que puedas, y deja que *args/**kwargs transporten solo entradas genuinamente variádicas o reenvío puro.
Los mensajes de error se vuelven imprecisos
Un nombre de palabra clave mal escrito se convierte en un None silencioso o en un KeyError dentro de la función, en lugar de un "unexpected keyword argument" inmediato en el sitio de la llamada. Los parámetros con nombre te dan mucho mejor feedback.
Como regla: prefiere parámetros con nombre por defecto, y recurre a *args/**kwargs solo cuando la función es genuinamente flexible o está reenviando argumentos a otro callable.
Un pequeño ejemplo práctico
Un helper de estilo plotting que envuelve una función de terceros con algunos valores por defecto:
*values permite a quien llama pasar cualquier número de elementos; **style absorbe configuración adicional sin requerir que cada opción sea un parámetro con nombre. Es flexible sin ser opaco, porque la lógica interna te dice exactamente qué claves lee de style.
Recapitulación
*argsempaqueta argumentos posicionales adicionales en una tupla.**kwargsempaqueta argumentos por palabra clave adicionales en un dict.- En el sitio de la llamada,
*seqy**dictdesempaquetan en sentido contrario. - Los parámetros deben aparecer en este orden: normales →
*args→ solo por palabra clave →**kwargs. - No abuses — los parámetros con nombre son más claros cuando puedes usarlos.
Lo siguiente: lambda, una forma de escribir funciones pequeñas y desechables en línea.
Preguntas frecuentes
¿Qué es *args en Python?
*args recoge cualquier argumento posicional adicional en una tupla. def f(*args): te permite llamar a f(1, 2, 3) y recibir args como (1, 2, 3). El nombre args es una convención — podrías llamarlo como quieras, pero *args es lo que todo el mundo usa.
¿Qué es **kwargs en Python?
**kwargs recoge cualquier argumento de palabra clave adicional en un dict. def f(**kwargs): te permite llamar a f(name='Ada', age=30) y recibir kwargs como {'name': 'Ada', 'age': 30}. Juntos, *args y **kwargs permiten que una función acepte cualquier combinación de argumentos.
¿Hay que llamarlos args y kwargs?
No, lo que importa son los asteriscos, no los nombres. *values y **options funcionan igual. Pero args y kwargs son una convención casi universal en código Python — úsalos salvo que tengas una razón concreta para elegir algo más descriptivo.