Copia superficial (shallow copy) crea un nuevo objeto de nivel superior, pero los objetos anidados (elementos de listas, diccionarios anidados, etc.) comparten memoria con el original. Copia profunda (deep copy) copia recursivamente todos los niveles de objetos.
Se puede usar a través del módulo copy:
import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # Cambia tanto original como shallow print(original) # [[99, 2], [3, 4]] # Ahora con deep original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]
copy.copy(obj): solo copia la "envoltura"copy.deepcopy(obj): copia recursiva completa¿Qué sucederá al copiar una tupla que contiene objetos mutables?
tuple es inmutable, pero sus elementos pueden ser mutables (por ejemplo, una lista). Shallow copy y deep copy difieren:
import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # Al hacer deep copy: t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])
Historia
En una aplicación de procesamiento de documentos, los datos se almacenaban en una lista dentro de un diccionario. Al copiar objetos con copy.copy, los elementos anidados se modificaban accidentalmente al modificar el nuevo objeto. Como resultado, los datos originales se cambiaron en otras partes del sistema. ¡Se produjo corrupción de datos! Se resolvió cambiando a deepcopy.
Historia
En un proyecto de aprendizaje automático, al guardar los hiperparámetros de los modelos, se copiaba la lista de configuraciones mediante asignación estándar y shallow copy, después de lo cual diferentes experimentos cambiaban mutuamente sus parámetros. La fuente del error se encontró tras diagnosticar el comportamiento de la copia de listas anidadas mediante deepcopy.
Historia
En un software financiero, se aplicó accidentalmente deep copy a un objeto que incluye un archivo abierto (handle), lo que provocó TypeError: cannot pickle '_io.TextIOWrapper' object — porque copy.deepcopy utiliza pickle bajo el capó. Se resolvió mediante un manejo explícito de tales campos o a través de la llamada a shallow copy.