Copia Superficial y Múltiples Nombres

En Python, un objeto puede tener múltiples nombres (también conocido como “aliasing” en inglés). Esto sucede con objetos mutables como listas. Un ejemplo sería:

a = [81, 82, 83]
b = a

State snapshot for multiple references (aliases) to a list

Desde enlace (íngles) http://interactivepython.org/courselib/static/thinkcspy/Lists/Aliasing.html

Tanto “b” como “a” se refieren al mismo objeto, así cualquier cambio en uno se refleja en el otro.

a.append(84)
print(b) #se muestra [81, 82, 83, 84]

Debido a este efecto secundario, puede haber problemas (errores inesperados) en tu código. La mejor práctica es hacer una copia de objetos cuando sea necesario. Para continuar con el ejemplo,

a = [81, 82, 83]
b = a[:]
a.append(84)
print(b) #se muestra [81, 82, 83]
print(a) #se muestra [81, 82, 83, 84]

Puedes hacer copias de listas y tuplas cuando usas [:] al final del objeto. También puedes hacer copias de los tipos datos dict y set, pero el formato es un poco diferente. Se usa el método copy(). Ejemplos:

c = (1, 2, 3)
d = c[:]
print(d) #se muestra (1, 2, 3)

e = {12, 14, 14, 25} #set elimina duplicados
f1 = e
f2 = e.copy()
e.add(23)
print(f1) #se muestra {12, 14, 25, 23}
print(f2) #se muestra {12, 14, 25}

g = {'ingles' : 'hello'}
h1 = g
h2 = g.copy()
g['espanol'] = 'hola'
print(h1) #se muestra {'ingles': 'hello', 'espanol': 'hola'}
print(h2) #se muestra {'ingles': 'hello'}

Es importante observar que desde tuplas son inmutable que no hay muchas razones para hacer copias de ellos porque no cambian. Esta forma de hacer copias de objetos está llamado hacer copia superficial. Cuando usas el método copy() o el sintasis [:], haces una copia superficial. Sin embargo, ¿Que es una copia profunda? ¿Cual es la importancia ? Y, ¿Cual es la diferencia de las copias superficiales?

Copia Profunda

En realidad, creo que IBM lo dice mejor:

Los términos copia superficial y copia profunda describen dos formas diferentes de copiar un elemento.

Copia superficial: una copia superficial crea un duplicado del elemento original (simple o complejo) pero no hace copias de ningún elemento al que el elemento original haga referencia. En lugar de esto, si el elemento original contiene una referencia a un objeto, la referencia correspondiente en el elemento copiado hace referencia al mismo objeto.

Copia profunda: una copia profunda no sólo copia el elemento original, sino también cualesquiera elementos a los que haga referencia el elemento original. Para cada referencia del elemento original, la operación de copia crea una instancia nueva del objeto al que se hace referencia, copia el contenido del objeto al que se hacer referencia en la instancia nueva del objeto y almacena una referencia a la instancia nueva del objeto en el elemento nuevo.

Los objetos a los que se hace referencia que a su vez contienen referencias se copian de la misma forma.

Sin embargo, lo explicaré de todas formas. La importancia de una copia profunda viene cuando estas usando un objeto compuesto, es decir, un objeto con objetos mutables dentro de él. Por ejemplo, una lista dentro de una lista o quizás solo un objeto de clase. Si hicieras una copia superficial de un objeto compuesto, el objeto sería copiado pero los objetos mutables adentro serían referenciados, lo que pueden causar efectos secundarios. Si haces una copia profunda, ese no sería el caso. Todos los objetos serían copiados.

¿Cómo te haces una copia profunda?

Es necesario que importas el modulo copy. Dentro del modul, hay un función copy() y un función deepcopy(). La función copy() te permite hacer copia superficial de objetos sin un método copy interno. Por otra parte, la función deepcopy() te permite hacer copia profunda. Ejemplos:

import copy

a = [[1, 2, 3], [4,5,6]]

b = a[:]
c = copy.deepcopy(a)
a.append[0][4]
print(b, c) #se muestra [[1, 2, 3, 4], [4,5,6]] [[1, 2, 3], [4,5,6]]

class Padre:
    def __init__(self, nombre):
        self.nombre = nombre
        self.nombres = [nombre]
    def __str__(self):
        return “Mi nombre es {0}. Soy un padre”.format(nombre)

    def cambiar(self, nueva):
        self.nombres.append(nueva)
        self.nombre = nueva

padre1 = Padre('Pablo')
padre2 = copy.copy(padre1)
padre3 = copy.deepcopy(padre1)
padre2.cambiar('Byron')

print(padre1) #se muestra “Mi nombre es Pablo. Soy un padre”
print(padre2) #se muestra “Mi nombre es Byron. Soy un padre”
print(padre1.nombres) #se muestra [“Pablo”, “Byron”]
print(padre2.nombres) #se muestra [“Pablo”, “Byron”]
print(padre3.nombres) #se muestra [“Pablo”]

Aunque solo cambiamos el nombre en el variable padre2, la lista nombres se cambió en padre1. Este se muestra la importancia de copia profunda.


Por mas información:

http://pyspanishdoc.sourceforge.net/lib/module-copy.html

http://pensandocomoprogramador.blogspot.com/2012/08/811-alias-poner-sobrenombres.html

05. Python: copia superficial y copia profunda

http://docs.python.org.ar/tutorial/3/classes.html

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *