A veces querrás una copia completa de un objeto, otras veces querrás que utilice referencias. Vea las diferencias en acción.
Python ofrece varios enfoques eficientes para la gestión de datos. Comprender los conceptos de copia superficial y profunda es fundamental cuando se trabaja con estructuras de datos como listas anidadas, diccionarios u objetos personalizados.
Tanto la copia superficial como la profunda le permiten crear réplicas de estructuras de datos, pero actúan de manera diferente con respecto a los datos anidados.
Usando copia superficial
La copia superficial funciona creando una copia de la estructura de nivel superior del objeto original. Esto significa que, si el objeto original contiene objetos anidados, la copia hará referencia a los mismos objetos anidados que el original. En otras palabras, hacer una copia superficial de un objeto duplica su estructura más externa, no los objetos anidados que pueda contener.
Para realizar una copia superficial en Python, puede utilizar el módulo de copia Copiar() función o la .Copiar() método sobre el objeto.
Considere un ejemplo de trabajar con una lista o diccionario en Python.
import copy
main_list = [29, 49, ["Q", "R"]]
shallow_copy = copy.copy(main_list)# Modify the nested list
shallow_copy[2][0] = 99
main_list[2][1] = 100
print(f"The main list: {main_list}")
print(f"The shallow copy list: {shallow_copy}")
En el código anterior, el lista_principal La variable contiene una lista que contiene números enteros y una lista interna (objeto anidado) que contiene letras. La función de copia crea una copia del lista_principal que el código almacena en otra variable, copia superficial.
Cualquier cambio que realice en el copia superficial lista anidada también afectará directamente a la del lista_principal y viceversa. Estos cambios muestran que la lista anidada o interna de la copia superficial es sólo una referencia a la del lista_principal, haciendo que los cambios se apliquen en lista_principal también.
Mientras tanto, cualquier cambio realizado en los elementos externos (los números enteros) en cualquiera de los dos copia superficial o lista_principal sólo afectará a esa instancia. Estos elementos externos son valores independientes por derecho propio, no meras referencias.
import copy
main_list = [29, 49, ["Q", "R"]]
shallow_copy = copy.copy(main_list)# Modify the outer items
shallow_copy[0] = "M"
main_list[1] = "N"
print(f"The main list: {main_list}")
print(f"The shallow copy list: {shallow_copy}")
El resultado demuestra que los elementos externos de ambas listas son independientes entre sí:
La misma idea se aplica cuando se trabaja con diccionarios.
dict1 = {'ten': 10, 'twenty': 20, 'double':{'thirty': 30, 'sixty': 60}}
dict2 = dict1.copy()# Modify inner and outer elements
dict1['double']['thirty'] = 30.00
dict1['ten'] = 10.00
print(f"The main dictionary, {dict1}")
print(f"The shallow copy dictionary, {dict2}")
Cambios realizados en el diccionario anidado de dict1 afectar a ambos dict1 y dict2. Al mismo tiempo, los cambios en los elementos exteriores de dict1 afectar sólo a él.
Usando copia profunda
En lugar de hacer referencia a los objetos anidados de la copia original, una copia profunda crea una copia completamente separada del objeto original y sus objetos anidados. Modificar la copia profunda no afectará el objeto original y viceversa; son valores verdaderamente separados.
Para hacer una copia profunda en Python, use el copia profunda() Función del módulo de copia.
Considere un ejemplo de cómo trabajar con una lista.
import copy
main_list = [200, 300, ["I", "J"]]
deep_copy = copy.deepcopy(main_list)# Modify the inner and outer list
deep_copy[2][0] = "K"
main_list[0] = 500
print(f"The main list: {main_list}")
print(f"The deep copy list: {deep_copy}")
Aquí, el código realiza una copia profunda de lista_principal, creando una copia independiente llamada copia_profunda.
Cuando modifica la lista anidada o los elementos externos en el copia_profunda, sus cambios no afectan la lista original y viceversa. Esto demuestra que la lista anidada o los elementos externos no se comparten entre las dos copias.
Trabajar con objetos personalizados
Puede crear un objeto personalizado definiendo una clase de Python y crear una instancia de la clase.
A continuación se muestra un ejemplo de cómo crear un objeto simple a partir de un Libro clase:
classBook:
def__init__(self, title, authors, price):
self.title = title
self.authors = authors
self.price = price
def__str__(self):
returnf"Book(title='{self.title}', author='{self.authors}', \
price='{self.price}')"
Ahora, haga una copia superficial y una copia profunda de una instancia de este Libro clase usando el Copiar módulo.
import copy
# Create a Book object
book1 = Book("How to MakeUseOf Shallow Copy", \
["Bobby Jack", "Princewill Inyang"], 1000)# Make a shallow copy
book2 = copy.copy(book1)# Modify the original object
book1.authors.append("Yuvraj Chandra")
book1.price = 50
# Check the objects
print(book1)
print(book2)
Como puede ver, la copia superficial (libro2) es un objeto nuevo, pero hace referencia al mismo objeto interno (lista de autores) que el objeto original (Libro 1). Por lo tanto, un cambio en los autores del objeto original afecta a ambas instancias (libro1 y libro2), mientras que un cambio en el elemento externo (precio) sólo afecta al objeto original (Libro 1).
Por otro lado, hacer una copia profunda crea una copia independiente del objeto original, incluidas copias de todos los objetos que contiene.
# Create a Book object
book1 = Book("Why MakeUseOf Deep Copy?", \
["Bobby Jack", "Yuvraj Chandra"], 5000)# Make a deep copy
book2 = copy.deepcopy(book1)# Modify the original object
book1.authors.append("Princewill Inyang")
book1.price = 60
# Check the objects
print(book1)
print(book2)
En este caso, la copia profunda (libro2) es un objeto completamente independiente, y modificando el objeto original (Libro 1) no lo afecta.
Usos de copia superficial y copia profunda
Es vital comprender la copia profunda y superficial para poder seleccionar el enfoque adecuado para manipular los datos. A continuación se muestran algunos escenarios en los que cada método es aplicable:
- Utilice una copia superficial si desea replicar un objeto complejo sin generar nuevas instancias de sus objetos anidados. Este enfoque es más eficiente en memoria y más rápido que la copia profunda porque no duplica objetos anidados.
- Utilice una copia superficial para crear una instantánea del estado de un objeto y al mismo tiempo compartir algunos datos subyacentes entre los objetos originales y copiados.
- Utilice una copia profunda si desea modificar una réplica de un objeto sin afectar el original. Esto genera copias independientes de objetos anidados, asegurando que cualquier cambio en la copia no se aplique al original.
- La copia profunda es fundamental cuando se necesitan copias independientes de estructuras de datos anidadas, principalmente cuando se trata de jerarquías de objetos recursivas o intrincadas.
Rendimiento y consideraciones
Dado que la copia superficial no genera nuevas instancias de objetos anidados, normalmente se ejecuta más rápido y utiliza menos memoria que la copia profunda. Sin embargo, el original y la copia superficial pueden tener efectos secundarios no deseados al cambiar elementos internos compartidos.
Particularmente para estructuras de datos grandes y profundamente anidadas, copia profunda, un procedimiento recursivo, puede ser más lento y utilizar más memoria. Sin embargo, garantiza una independencia total entre el original y el duplicado profundo, lo que hace que la manipulación de datos complejos sea más segura.
La mejor opción de copia para sus datos
Muchos lenguajes de programación utilizan el concepto de copia superficial y profunda. Comprenderlo le permite manipular datos sin consecuencias imprevistas.
Al utilizar técnicas de copia superficial y profunda, puede seleccionar el mejor enfoque para duplicar sus estructuras de datos de forma segura. Al comprender los efectos en sus datos, obtendrá resultados más confiables y predecibles de su código.