ProgrammazioneSviluppatore Backend

Qual è la differenza tra shallow e deep copy nella struttura dict e come copiare correttamente i dizionari annidati in Python?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Storia della domanda

In Python, la struttura dati dict viene spesso utilizzata per memorizzare informazioni annidate. Gli sviluppatori si trovano spesso di fronte alla necessità di clonare tali strutture quando lavorano con modelli, configurazioni o trasferimento di dati tra parti dell'applicazione.

Problema

La copia standard di un dict tramite assegnazione (=) crea solo un riferimento all'oggetto originale. La copia superficiale (shallow copy) copia solo l'oggetto dict, ma non gli oggetti annidati. La copia profonda (deep copy) copia ricorsivamente tutti gli oggetti interni, prevenendo l'influenza delle modifiche in una copia sull'altra.

Soluzione

Per la copia superficiale si può utilizzare dict.copy() o il costruttore dict(), per la copia profonda — il modulo copy e la funzione deepcopy():

import copy d = {"a": 1, "b": {"c": 2}} shallow_d = d.copy() deep_d = copy.deepcopy(d) # Ora la modifica di shallow_d['b']['c'] influenzerà d['b']['c'] # la modifica di deep_d['b']['c'] non influenzerà il dizionario originale

Caratteristiche chiave:

  • La copia superficiale copia solo il primo "guscio" dell'oggetto
  • La copia profonda copia ricorsivamente tutti gli oggetti all'interno della struttura
  • Quando si lavora con strutture annidate, utilizzare sempre deepcopy se è necessaria una completa indipendenza della copia

Domande insidiose.

Può dict.copy() copiare livelli più profondi del primo livello?

No, dict.copy() crea solo una copia superficiale. I dizionari annidati saranno comunque riferimenti agli stessi oggetti del dict originale.

Se nella struttura c'è un oggetto immutabile (ad esempio una tupla), deepcopy lo copierà profondamente?

Deepcopy copia solo gli oggetti annidati mutabili. Gli oggetti immutabili rimangono tali: tuple, stringhe e numeri non vengono copiati ricorsivamente, ma vengono semplicemente trasferiti nella copia.

Si può utilizzare la serializzazione attraverso json.loads(json.dumps(dict)) per la copia profonda?

Sì, ma con alcune limitazioni. Questo metodo funziona solo per tipi serializzabili e non è adatto se nel dizionario ci sono oggetti non serializzabili (come funzioni o classi personalizzate):

import json orig = {"a": 10, "b": [1,2,3]} copy_like_deep = json.loads(json.dumps(orig)) # Non funziona per oggetti complessi

Errori tipici e anti-pattern

  • Utilizzo di semplice assegnazione invece della copia
  • Applicazione di copia superficiale a strutture annidate, che porta a modifiche inaspettate in tutte le "copie"

Esempio dalla vita reale

** Caso negativo Uno sviluppatore clona le impostazioni tramite copy(), quindi modifica un valore annidato, pensando che si tratti di due strutture indipendenti. Vantaggi: Facile e veloce Svantaggi: Le modifiche agli oggetti annidati in una copia si riflettono su tutte — bug difficili da debug. ** Caso positivo Uno sviluppatore utilizza sempre copy.deepcopy() per le strutture annidate, anche se il dict originale sembra piatto. Vantaggi: Indipendenza garantita dei dati, bug ridotti al minimo Svantaggi: Deepcopy è più lento e consuma più memoria, a volte è eccessivo.