*args raccoglie un numero arbitrario di argomenti posizionali in una tupla.
**kwargs raccoglie un numero arbitrario di argomenti nominati (chiave=valore) in un dizionario.
Questo permette di scrivere funzioni con un'interfaccia flessibile:
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}
Aspetti da considerare:
È possibile cambiare l'ordine di *args e argomenti nominati con un valore di default, ad esempio:
def foo(a, *args, x=10, **kwargs): pass
oppure è sempre necessario mettere i valori di default dopo *args?
Risposta:
In Python 3 sì! Ecco come (non funzionava in Python 2):
def foo(a, *args, x=10): pass
I parametri dopo *args ("keyword-only arguments") possono avere valori di default o essere obbligatori — possono essere specificati solo per nome.
Storia
Passaggio di argomenti errati tramite *args/**kwargs
Nei servizi REST API, l'automazione del marshalling dei dati era costruita tramite **kwargs. Un parametro superfluo non è stato notato — la funzione accettava un valore inaspettato in kwargs, causando la perdita della logica di controllo e bug difficili da individuare.
Storia
Duplicazione di argomenti nominati
Quando la funzione è stata chiamata, lo sviluppatore ha accidentalmente specificato un parametro sia esplicitamente che tramite **kwargs, ad esempio: my_func(a=1, **{"a": 2}). Di conseguenza, si è verificato un TypeError e il servizio è caduto.
Storia
Dimenticati argomenti posizionali o solo nominati
Scrivendo un decoratore, un passaggio errato dei parametri (non seguendo l'ordine e la struttura) ha portato a far sì che la funzione originale ricevesse un numero errato di argomenti, le cui convenzioni cambiavano, e in produzione hanno iniziato a sorgere errori di chiamata TypeError.