*args — recopila una cantidad arbitraria de argumentos posicionales en una tupla.
**kwargs — recopila una cantidad arbitraria de argumentos nombrados (clave=valor) en un diccionario.
Esto permite escribir funciones con una interfaz flexible:
def my_func(a, b, *args, **kwargs): print(a, b) print(args) print(kwargs) my_func(1, 2, 3, 4, x=10, y=20) # 1 2 # (3, 4) # {'x': 10, 'y': 20}
Detalles:
¿Se puede cambiar el orden de *args y los argumentos nombrados con valor por defecto, por ejemplo:
def foo(a, *args, x=10, **kwargs): pass
¿o necesariamente siempre deben colocarse los valores por defecto después de *args?
Respuesta:
¡En Python 3 se puede! Así (no funcionaba en Python 2):
def foo(a, *args, x=10): pass
Los parámetros después de *args ("argumentos solo por palabra clave") pueden tener valores por defecto o ser obligatorios — solo se pueden especificar por nombre.
Historia
Pasar argumentos incorrectos a través de *args/**kwargs
En servicios REST API, la automatización del marshalling de datos se construyó a través de **kwargs. Un parámetro adicional no fue notado — la función aceptó un valor inesperado en kwargs, lo que llevó a la pérdida de lógica de control y errores difíciles de depurar.
Historia
Duplicación de argumentos nombrados
Al llamar a la función, el desarrollador accidentalmente especificó un parámetro tanto de forma explícita como a través de **kwargs, por ejemplo: my_func(a=1, **{"a": 2}). Como resultado — TypeError y caída del servicio.
Historia
Olvidaron argumentos posicionales o solo nombrados
Al escribir un decorador, la transmisión incorrecta de parámetros (no se cumplió el orden y la estructura) llevó a que la función original recibiera un número incorrecto de argumentos, cuyos acuerdos cambiaron, y en producción comenzaron a surgir errores de llamada TypeError.