Python *args y **kwargs
Aprende cómo *args y **kwargs permiten que las funciones de Python acepten cualquier número de argumentos posicionales y de palabra clave, con ejemplos reales.
*args y **kwargs son sintaxis especiales en Python que permiten a una función aceptar un número variable de argumentos. *args recoge los argumentos posicionales adicionales en una tupla, mientras que **kwargs recoge los argumentos de palabra clave adicionales en un diccionario. Juntos ofrecen total flexibilidad: puedes escribir funciones que funcionen con uno o cien argumentos.
Esta página cubre ambas características en profundidad: cómo funcionan, cuándo usarlas, cómo combinarlas y los errores comunes que debes evitar.
¿Qué es *args?
Cuando antepones un asterisco simple (*) al nombre de un parámetro, Python recoge todos los argumentos posicionales adicionales pasados a la función en una tupla enlazada a ese nombre de parámetro. El nombre args es una convención — podrías escribir *numbers o *values — pero *args es universalmente comprendido.
def add_all(*args):
total = 0
for n in args:
total += n
return total
print(add_all(1, 2, 3)) # 6
print(add_all(10, 20, 30, 40)) # 100
print(add_all()) # 0Dentro de la función, args es una tupla ordinaria que puedes recorrer, indexar o pasar a otras funciones. Llamar a add_all() con cero argumentos es válido — args es simplemente una tupla vacía.
Combinar parámetros regulares con *args
Los parámetros regulares (posicionales) van primero; *args captura todo lo que sigue:
def greet(greeting, *names):
for name in names:
print(greeting + ', ' + name + '!')
greet('Hello', 'Alice', 'Bob', 'Charlie')
# Hello, Alice!
# Hello, Bob!
# Hello, Charlie!greeting se rellena con el primer argumento; names recibe el resto como una tupla. Si llamas a greet('Hi') sin nombres adicionales, names es una tupla vacía y el bucle simplemente no se ejecuta — sin error.
¿Qué es **kwargs?
Dos asteriscos (**) antes del nombre de un parámetro le indican a Python que recoja todos los argumentos de palabra clave adicionales en un diccionario. Nuevamente, kwargs es una convención; cualquier identificador Python válido funciona.
def describe(**kwargs):
for key, value in kwargs.items():
print(key + ': ' + str(value))
describe(name='Alice', age=30, city='New York')
# name: Alice
# age: 30
# city: New YorkDentro de la función, kwargs es un diccionario ordinario. Puedes recorrerlo, buscar claves o pasarlo. El llamador decide qué claves proporcionar — ninguna está fijada por la definición de la función.
Cuándo usar **kwargs
**kwargs destaca cuando:
- Una función necesita aceptar un conjunto flexible y abierto de opciones con nombre (configuración, metadatos, atributos HTML).
- Estás escribiendo un envoltorio que debe reenviar argumentos de palabra clave a otra función sin saber cuáles son.
- Quieres construir un diccionario a partir de argumentos de palabra clave de forma legible (evita el código repetitivo de
dict(key=value, ...)).
Combinar *args y **kwargs
Una sola función puede aceptar argumentos posicionales ilimitados y argumentos de palabra clave ilimitados. El orden requerido en la firma es:
- Parámetros posicionales normales
*args- Parámetros de solo palabra clave (con valores por defecto)
**kwargs
def log_event(event, *tags, **metadata):
print('Event:', event)
print('Tags:', tags)
print('Metadata:', metadata)
log_event('login', 'auth', 'user', user_id=42, ip='127.0.0.1')
# Event: login
# Tags: ('auth', 'user')
# Metadata: {'user_id': 42, 'ip': '127.0.0.1'}event toma el primer argumento posicional; tags captura los argumentos posicionales restantes; metadata captura todos los argumentos de palabra clave.
Desempaquetar argumentos con * y **
Los operadores * y ** no son solo para definiciones de funciones — también funcionan en el lado de la llamada para desempaquetar secuencias y mapeos en argumentos separados.
Desempaquetar una lista o tupla con *
def multiply(a, b, c):
return a * b * c
nums = [2, 3, 4]
print(multiply(*nums)) # 24*nums desempaqueta la lista de modo que a=2, b=3, c=4. Esto es equivalente a escribir multiply(2, 3, 4). Consulta Desempaquetar tuplas para más información sobre el operador de desempaquetado.
Desempaquetar un diccionario con **
def power(base, exp):
return base ** exp
params = {'base': 3, 'exp': 4}
print(power(**params)) # 81**params asigna cada clave del diccionario al nombre de parámetro correspondiente. Esto es útil cuando los argumentos se almacenan en un diccionario de configuración construido en tiempo de ejecución.
Argumentos de solo palabra clave después de *args
Cualquier parámetro listado después de *args en la firma solo puede pasarse por nombre (se convierte en un argumento de solo palabra clave). Esta es una forma limpia de agregar indicadores opcionales sin ambigüedad:
def configure(host, *args, port=80, debug=False):
print('host:', host)
print('extra:', args)
print('port:', port)
print('debug:', debug)
configure('localhost', 'arg1', port=8080, debug=True)
# host: localhost
# extra: ('arg1',)
# port: 8080
# debug: Trueport y debug no pueden establecerse de forma posicional porque *args ya consume todo el desbordamiento posicional. Este patrón es común en las API de bibliotecas — los usuarios deben escribir port=8080 explícitamente, lo que hace que los sitios de llamada sean autodocumentados.
Para una explicación detallada de las reglas de ámbito de Python, consulta Ámbito en Python.
Reenviar argumentos a otra función
Uno de los usos más prácticos de *args/**kwargs es escribir envoltorios y decoradores que pasen argumentos a una función interna sin saber cuáles son esos argumentos:
def add_all(*args):
return sum(args)
def wrapper(*args, **kwargs):
print('Calling with args:', args, 'kwargs:', kwargs)
return add_all(*args)
print(wrapper(1, 2, 3))
# Calling with args: (1, 2, 3) kwargs: {}
# 6Este patrón aparece en toda la biblioteca estándar de Python y es la base de los decoradores y las funciones de orden superior.
Orden completo de la firma
Python impone una regla de ordenamiento estricta para todos los tipos de parámetros. El orden completo es:
| Posición | Tipo | Ejemplo |
|---|---|---|
| 1 | Solo posicional (Python 3.8+) | a, b, / |
| 2 | Posicional o de palabra clave normal | x, y |
| 3 | Posicional variable | *args |
| 4 | Solo palabra clave | flag=True |
| 5 | Palabra clave variable | **kwargs |
Romper este orden produce un SyntaxError. Una función que usa los cinco tipos se ve así:
def full_sig(pos1, pos2, /, normal, *args, kw_only, **kwargs):
print(pos1, pos2, normal, args, kw_only, kwargs)
full_sig(1, 2, 3, 4, 5, kw_only='k', extra='e')
# 1 2 3 (4, 5) k {'extra': 'e'}En el código cotidiano raramente necesitas los cinco a la vez. Los patrones más comunes son *args solo, **kwargs solo, o *args seguido de **kwargs.
Anotaciones de tipo
Puedes anotar *args y **kwargs con sugerencias de tipo. La anotación se aplica a cada elemento individual, no a la tupla o diccionario en sí:
from typing import Any
def add_all(*args: float) -> float:
return sum(args)
def describe(**kwargs: Any) -> None:
for key, value in kwargs.items():
print(f'{key}: {value}')
print(add_all(1.5, 2.5, 3.0)) # 7.0
describe(name='Bob', score=99)
# name: Bob
# score: 99*args: float significa que se espera que cada elemento de args sea un float. **kwargs: Any significa que los valores pueden ser cualquier cosa. Esto mantiene satisfechas a las herramientas de análisis estático mientras se preserva la flexibilidad en tiempo de ejecución.
Errores comunes
1. Orden incorrecto de argumentos en la firma
Poner **kwargs antes de *args es un SyntaxError:
# Wrong — raises SyntaxError
# def bad(name, **kwargs, *args): ...
# Correct
def good(name, *args, **kwargs):
pass2. Mutar la tupla args
args es una tupla y por lo tanto es inmutable. Si necesitas modificar los argumentos, conviértelos primero a una lista:
def double_all(*args):
items = list(args) # mutable copy
items = [x * 2 for x in items]
return items
print(double_all(1, 2, 3)) # [2, 4, 6]3. Sombrear el nombre de un parámetro requerido
Si usas *args y también tienes un argumento de palabra clave con el mismo nombre que un parámetro posicional, los llamadores pueden confundirse. Mantén los nombres de parámetros distintos y usa parámetros de solo palabra clave (después de *args) para los indicadores opcionales.
4. Abusar de **kwargs en lugar de parámetros explícitos
**kwargs oculta lo que una función realmente acepta, dificultando el autocompletado y el análisis estático. Prefiere parámetros explícitos para las opciones que tu función genuinamente admite; usa **kwargs solo cuando el conjunto de opciones es verdaderamente abierto o cuando reenvías a otra función.
Resumen
| Característica | Sintaxis | Qué recoge | Tipo dentro de la función |
|---|---|---|---|
| Args posicionales variables | *args | Argumentos posicionales adicionales | tuple |
| Args de palabra clave variables | **kwargs | Argumentos de palabra clave adicionales | dict |
| Desempaquetar secuencia en la llamada | func(*seq) | Lista/tupla → args posicionales | — |
| Desempaquetar mapeo en la llamada | func(**mapping) | Dict → args de palabra clave | — |
Para temas estrechamente relacionados, consulta Funciones de Python para los conceptos básicos de funciones, Python Lambda para funciones anónimas, y Ámbito en Python para cómo Python resuelve los nombres de variables.