Lección 2 · 2 de 20
*args, **kwargs y argumentos por nombre · Python
Funciones de Python que aceptan cualquier número de argumentos con *args y **kwargs, y argumentos que solo se pasan por nombre.

invoice_total(*amounts, ...) acepta tantos importes como se le pasen: el asterisco los reúne en una tupla llamada amounts, y sum(amounts) los suma. Por eso funciona igual con tres importes que con uno.
Los parámetros que van detrás de *amounts (discount y tax) son solo por nombre (*keyword-only*): no hay manera de pasarlos por posición, porque todo lo posicional ya se lo queda *amounts. Hay que escribir discount=0.1 o tax=0.10, y eso hace la llamada más clara.
log_event(event, **details) recibe los argumentos con nombre que sobran en un diccionario. El programa lo recorre con details.items() para escribir cada campo como clave=valor.
Los asteriscos también sirven al llamar: invoice_total(*prices) reparte la lista como argumentos sueltos y log_event("update", **extra) reparte un diccionario como argumentos con nombre.
En ship(order_id, *, express=False) el * solo no recoge nada: marca que lo que viene detrás va por nombre. Por eso ship(1043, True) lanza un TypeError, que el programa captura y muestra.
Código · main.py
def invoice_total(*amounts, discount=0.0, tax=0.21): """Any number of amounts; discount and tax are keyword-only.""" net = sum(amounts) * (1 - discount) return round(net * (1 + tax), 2)def log_event(event, **details): """Extra named arguments arrive in a dict.""" fields = ", ".join(f"{key}={value}" for key, value in details.items()) print(f"[{event}] {fields}")def ship(order_id, *, express=False): """The bare * makes express keyword-only.""" speed = "express" if express else "standard" print(f"Order {order_id} ships by {speed} delivery")print("Total:", invoice_total(100, 50, 25))print("With 10% off:", invoice_total(100, 50, 25, discount=0.1))print("Reduced tax:", invoice_total(80, tax=0.10))prices = [19.99, 5.01, 75.0]print("From a list:", invoice_total(*prices)) # unpack a list into *amountslog_event("login", user="ana", ip="10.0.0.7")extra = {"order": 1042, "status": "shipped"}log_event("update", **extra) # unpack a dict into **detailsship(1042, express=True)try: ship(1043, True) # positional: not allowedexcept TypeError as error: print("Error:", error)Salida · python3 main.py
Total: 211.75 With 10% off: 190.57 Reduced tax: 88.0 From a list: 121.0 [login] user=ana, ip=10.0.0.7 [update] order=1042, status=shipped Order 1042 ships by express delivery Error: ship() takes 1 positional argument but 2 were given
Para recordar
*argsreúne los argumentos posicionales sobrantes en una tupla.**kwargsreúne los argumentos con nombre sobrantes en un diccionario.- Lo que va detrás de
*o de*argssolo se pasa por nombre. - Al llamar,
*listay**dicreparten los valores. - Los nombres
argsykwargsson costumbre; lo que importa son los asteriscos.
Ejercicio
Añada a invoice_total un parámetro solo por nombre shipping=0.0 que se sume al final, y llámelo con shipping=4.95.