Storia della domanda:
Gli operatori * e ** per lo spacking sono stati introdotti in Python da tempo, ma il loro utilizzo si è ampliato con ogni versione (ad esempio, a partire da Python 3.5 è stato aggiunto il supporto per l'unione di più collezioni tramite * e **). Questi operatori rendono il lavoro con le collezioni più flessibile, anche nella trasmissione di argomenti e nella loro raccolta nelle funzioni.
Problema:
Senza lo spacking, quando si lavora con sequenze dinamiche e si trasmettono parametri con un numero variabile di argomenti, è necessario scrivere manualmente cicli e controllare le dimensioni delle collezioni. Gli errori possono facilmente insorgere quando vengono usati in modo errato o quando non si distingue tra le funzioni di * e **.
Soluzione:
L'operatore * è destinato a spacking di sequenze (list, tuple, set), mentre l'operatore ** è utilizzato per spacking di dizionari durante le chiamate alle funzioni o per unire più dizionari. Essi permettono di trasmettere argomenti in modo elegante, effettuare fusioni di collezioni, e trasformare facilmente strutture arbitrari in parametri di funzione.
Esempio di codice:
def foo(a, b, c): print(a, b, c) args = (1, 2, 3) foo(*args) # 1 2 3 params = {'a': 10, 'b': 20, 'c': 30} foo(**params) # 10 20 30 list1 = [1, 2] list2 = [3, 4] combined = [*list1, *list2] print(combined) # [1, 2, 3, 4]
Caratteristiche chiave:
*sequence trasmette gli elementi come argomenti posizionali separati, **dict come argomenti nominati.[*a, *b] e {**d1, **d2}.È possibile utilizzare * e ** per collezioni miste?
Durante la chiamata di funzione, * funziona solo con argomenti posizionali, mentre ** solo con argomenti nominati. Se si passa un dict non spacked come * o una sequenza come **, si verificherà un errore.
def foo(a, b): print(a, b) foo(*{'a': 1, 'b': 2}) # Stampa: a b (chiavi del dizionario, non valori!)
**Cosa succede se i nomi delle chiavi si sovrappongono durante l'unione dei dict tramite {**d1, d2}?
Il risultato sarà il valore dell'ultimo dizionario con quella chiave.
d1 = {'x': 1, 'y': 2} d2 = {'y': 33, 'z': 44} merged = {**d1, **d2} print(merged) # {'x': 1, 'y': 33, 'z': 44}
È possibile utilizzare * e ** all'interno di espressioni di liste o dizionari?
Sì, ciò è legittimo a partire da Python 3.5, ad esempio:
lst = [1, 2, *range(3, 6)] # [1, 2, 3, 4, 5] dct = {**{'a': 1}, 'b': 2, **{'c': 3}}
Un sviluppatore accetta un dict in una funzione e lo analizza usando * invece di **. Si verifica un comportamento inaspettato: nella funzione arrivano le chiavi, non i valori.
Pro:
Il codice non fallisce immediatamente, sembra "funzionante".
Contro:
Errori nascosti e incongruenze nella logica attesa.
Trasmissione corretta dei parametri tramite **kwargs, fusione accurata dei dizionari, utilizzo di * per unioni dinamiche delle sequenze.
Pro:
Massima flessibilità, concisione del codice, semplicità di refactoring.
Contro:
Con un numero elevato di parametri e collezioni, è importante prestare attenzione ai nomi e all'ordine, altrimenti possono verificarsi errori.