2009-05-08 29 views
19

me preguntaba en ¿cómo funciona exactamente deepcopy en el siguiente contexto:diccionario de Python deepcopy

from copy import deepcopy 

def copyExample: 
    self.myDict = {} 
    firstPosition = "First" 
    firstPositionContent = ["first", "primero"] 
    secondPosition = "Second" 
    secondPositionContent = ["second"] 
    self.myDict[firstPosition] = firstPositionContent 
    self.myDict[secondPosition] = secondPositionContent 
    return deepcopy(self.myDict) 

def addExample(self): 
    copy = self.copyExample() 
    copy["Second"].add("segundo") 

¿Vuelve la referencia a las listas que tengo en el diccionario? ¿O funciona como espero y copia cada lista en una nueva lista con una referencia diferente?

Sé lo que es una copia profunda (así que no hay necesidad de explicar la diferencia entre profunda y superficial) pero me pregunto si funciona como espero y, por lo tanto, no modifico la variable de instancia cuando uso addExample().

+1

¿Ha impreso los dos diccionarios para ver si son diferentes? ¿Qué viste? ¿Eran diferentes? Si es así, la copia tiene una nueva lista a la que agregó un elemento. –

Respuesta

15

El documentation deja muy claro que está obteniendo copias nuevas, no referencias. Deepcopy crea copias en profundidad para tipos incorporados, con varias excepciones, y puede agregar operaciones de copia personalizadas a los objetos definidos por el usuario para obtener una copia profunda de soporte para ellos también. Si no estás seguro, bueno para eso es para lo que son las pruebas unitarias.

+0

No creo que indique tipos incorporados, dice que sí "copia" los objetos seleccionables ... ¿Eso significa que obtendré una nueva referencia de lista? – mandel

+7

Deepcopy tiene una breve lista de excepciones. Todo lo demás está copiado. "Este módulo no copia tipos como módulo, método, seguimiento de pila, marco de pila, archivo, socket, ventana, matriz o cualquier tipo similar". Obtienes una nueva lista. No es una referencia a la lista sino una nueva lista. Imprima los dos diccionarios de su ejemplo y mírelos. –

2

Sé que no está respondiendo a su pregunta, pero creo que es notable para las personas que miran esta pregunta.

Si los datos que está copiando son de naturaleza simple, la copia en profundidad puede ser excesiva. De naturaleza simple me refiero a si sus datos son representables como Json. Déjame ilustrar con el código:

He usado http://www.json-generator.com/ para obtener algunos datos de muestra json.

def deepCopyList(inp): 
    for vl in inp: 
     if isinstance(vl, list): 
      yield list(deepCopyList(vl)) 
     elif isinstance(vl, dict): 
      yield deepCopyDict(vl) 

def deepCopyDict(inp): 
    outp = inp.copy() 
    for ky, vl in outp.iteritems(): 
     if isinstance(vl, dict): 
      outp[ky] = deepCopyDict(vl)  
     elif isinstance(vl, list): 
      outp[ky] = list(deepCopyList(vl)) 
    return outp 

def simpleDeepCopy(inp): 
    if isinstance(inp, dict): 
     return deepCopyDict(inp) 
    elif isinstance(inp, list): 
     return deepCopyList(inp) 
    else: 
     return inp 

if __name__ == '__main__': 
    import simplejson as json 
    import time 
    from copy import deepcopy 
    fl = open('sample.json', 'r') 
    sample = json.load(fl) 
    start = time.time() 
    for _ in xrange(10000): 
     tmp = simpleDeepCopy(sample) 
    end = time.time() 
    print 'simpleDeepCopy: ' + str(end - start) 
    start = time.time() 
    for _ in xrange(10000): 
     tmp = deepcopy(sample) 
    end = time.time() 
    print 'copy.deepcopy: ' + str(end - start) 

de salida:

simpleDeepCopy: 0.0132050514221 
copy.deepcopy: 2.66142916679 

simpleDeepCopy: 0.0128579139709 
copy.deepcopy: 2.60736298561 
+0

"Con simple en la naturaleza me refiero a si sus datos son representables como Json" - esa es una declaración incorrecta: incluso algunos objetos simples, "JSON-able" pueden necesitar '.deepcopy()' para evitar referencias. Intenta esto: 'a = {1: 'A', 2: ['a', 'b', 'c'], 3: 'Z'}; b = a.copy(); a [2] .append ('d'); print b' – MestreLion

+0

Si los datos son representables como JSON, ¿por qué no usar 'json.loads (json.dumps (data))' ..? – rob