2009-12-23 22 views
7
from copy import* 
a=[1,2,3,4] 
c={'a':'aaa'} 
print c 
#{'a': 'aaa'} 
b=deepcopy(a,c) 
print b 

print c 
# print {'a': 'aaa', 10310992: 3, 10310980: 4, 10311016: 1, 11588784: [1, 2, 3, 4, [1, 2, 3, 4]], 11566456: [1, 2, 3, 4], 10311004: 2} 

qué Tipo C que¿Cuál es el propósito del segundo parámetro de deepcopy, memo?

Por favor, intente utilizar el código, en lugar de texto, porque mi Inglés no es muy bueno, gracias

en django.utils.tree.py

def __deepcopy__(self, memodict): 
     """ 
     Utility method used by copy.deepcopy(). 
     """ 
     obj = Node(connector=self.connector, negated=self.negated) 
     obj.__class__ = self.__class__ 
     obj.children = deepcopy(self.children, memodict) 
     obj.subtree_parents = deepcopy(self.subtree_parents, memodict) 
     return obj 



import copy 
memo = {} 
x1 = range(5) 
x2=range(6,9) 
x3=[2,3,4,11] 
y1 = copy.deepcopy(x1, memo) 
y2=copy.deepcopy(x2, memo) 
y3=copy.deepcopy(x3,memo) 
print memo 
print id(y1),id(y2),id(y3) 
y1[0]='www' 
print y1,y2,y3 
print memo 

de impresión:

{10310992: 3, 10310980: 4, 10311016: 1, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10311004: 2} 
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10310932: 8, 10311004: 2} 
11572408 11581280 11580960 
['www', 1, 2, 3, 4] [6, 7, 8] [2, 3, 4, 11] 
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: ['www', 1, 2, 3, 4], 10310932: 8, 10311004: 2} 

Respuesta

7

Es el memo dict, donde se guarda la correspondencia entre el objeto y el objeto para reconstruir perfectamente los gráficos complejos de objetos. Difícil "utilizar el código", pero, vamos a tratar:

>>> import copy 
>>> memo = {} 
>>> x = range(5) 
>>> y = copy.deepcopy(x, memo) 
>>> memo 
{399680: [0, 1, 2, 3, 4], 16790896: 3, 16790884: 4, 16790920: 1, 
438608: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 16790932: 0, 16790908: 2} 
>>> 

y

>>> id(x) 
399680 
>>> for j in x: print j, id(j) 
... 
0 16790932 
1 16790920 
2 16790908 
3 16790896 
4 16790884 

con el fin de que vea los ID son exactamente correcto. También:

>>> for k, v in memo.items(): print k, id(v) 
... 
399680 435264 
16790896 16790896 
16790884 16790884 
16790920 16790920 
438608 435464 
16790932 16790932 
16790908 16790908 

ve la identidad de los enteros (inmutables).

Así que aquí es un gráfico:

>>> z = [x, x] 
>>> t = copy.deepcopy(z, memo) 
>>> print id(t[0]), id(t[1]), id(y) 
435264 435264 435264 

para que veas todos los subcopies son los mismos objetos como y (ya que reutilizado el memo).

+0

¿Cómo puedo usar 'memo' correctamente cuando se copian con profundidad conjuntos de objetos con referencias entre sí? http://stackoverflow.com/q/41395369/2745116 – CGFoX

+0

Nota al margen: la copia directa de ints y otras primitivas inmutables es un [caso especial de 'deepcopy'] (https://github.com/python/cpython/blob/ 3.6/Lib/copy.py # L195) para evitar asignaciones de memoria. int literales fuera de 0-256 creará nuevos PyObjects cada vez. [Aquí hay una demostración] (https://gist.github.com/theY4Kman/da91d297cb27bb5e041702694b837fef). – theY4Kman

3

puede leer más marcando la onlin Python e documentación:

http://docs.python.org/library/copy.html

La función deepcopy() es recursivo, y funcionará su camino hacia abajo a través de un objeto anidado. Utiliza un diccionario para detectar objetos que ha visto antes, para detectar un bucle infinito. Solo debes ignorar este diccionario.

class A(object): 
    def __init__(self, *args): 
     self.lst = args 

class B(object): 
    def __init__(self): 
     self.x = self 

def my_deepcopy(arg): 
    try: 
     obj = type(arg)() # get new, empty instance of type arg 
     for key in arg.__dict__: 
      obj.__dict__[key] = my_deepcopy(arg.__dict__[key]) 
     return obj 
    except AttributeError: 
     return type(arg)(arg) # return new instance of a simple type such as str 

a = A(1, 2, 3) 
b = B() 
b.x is b # evaluates to True 
c = my_deepcopy(a) # works fine 
c = my_deepcopy(b) # stack overflow, recurses forever 

from copy import deepcopy 
c = deepcopy(b) # this works because of the second, hidden, dict argument 

Simplemente ignore el segundo argumento, oculto, dict. No intentes usarlo

0

Aquí es una ilustración rápida utilicé para explicar esto a mí mismo:

a = [1,2,3] 
memo = {} 
b = copy.deepcopy(a,memo) 
# now memo = {139907464678864: [1, 2, 3], 9357408: 1, 9357440: 2, 9357472: 3, 28258000: [1, 2, 3, [1, 2, 3]]} 

key = 139907464678864 
print(id(a) == key)    #True 
print(id(b) == key)    #False 
print(id(a) == id(memo[key]))  #False 
print(id(b) == id(memo[key]))  #True 

en otras palabras:

memo[id_of_initial_object] = copy_of_initial_object 
0

nadie por encima dio un buen ejemplo de cómo usarlo.

Aquí es lo que hago:

def __deepcopy__(self, memo): 
    copy = type(self)() 
    memo[id(self)] = self 
    copy._member1 = self._member1 
    copy._member2 = deepcopy(self._member2, memo) 
    return copy 

Dónde member1 es un objeto que no requieren deepcopy (como una cadena o un entero), y member2 es uno que lo haga, como otro tipo personalizado o una lista o dict.

He utilizado el código anterior en gráficos de objetos muy enredados y funciona muy bien.

Si también quiere hacer sus clases pickleable (para guardar archivo/carga), no hay parámetro nota análoga para getState/setstate, en otras palabras, el sistema de salmuera de alguna manera mantiene un registro de los objetos ya mencionados , entonces no necesitas preocuparte.

Los trabajos anteriores sobre las clases PyQt5 que se hereda de (así como decapado - por ejemplo, que puede DeepCopy o escabeche un QMainWindow encargo, QWidget, QGraphicsItem, etc.)

si hay algún código de inicialización en su constructor que crea objetos nuevos, por ejemplo, un CustomWidget (QWidget) que crea un nuevo CustomScene (QGraphicsScene), pero desea seleccionar o copiar la escena de un CustomWidget a uno nuevo; luego, una forma es crear un parámetro new=True en su __init__ y dicen:

def __init__(..., new=True): 
    .... 
    if new: 
     self._scene = CustomScene() 

def __deepcopy__(self, memo): 
    copy = type(self)(..., new=False) 
    .... 
    copy._scene = deepcopy(self._scene, memo) 
    .... 

que asegure ¡no crea un CustomScene (o una gran clase que hace muchas inicializaciones) dos veces! También debe utilizar la misma configuración (new=False) en su método __setstate__, por ejemplo .:

def __setstate__(self, data): 
    self.__init__(...., new=False) 
    self._member1 = data['member 1'] 
    ..... 

Hay otras maneras de conseguir alrededor de la anterior, pero esta es la que convergieron para uso y frecuencia.

¿Por qué hablé sobre decapado también? Porque querrá ambos en cualquier aplicación, y usted los mantiene al mismo tiempo. Si agrega un miembro a su clase, lo agrega a setstate, getstate, y código de copia profunda. Yo diría que para cualquier clase nueva que hagas, creas los tres métodos anteriores si planeas copiar/pegar un archivo guardar/cargar en tu aplicación. La alternativa es JSON y guardar/cargar usted mismo, pero luego hay mucho más trabajo que hacer, incluida la memorización.

a que apoyen todo lo anterior, es necesario __deepcopy__, __setstate__, and __getstate__ métodos y para importar deepcopy:

from copy import deepcopy 

, y cuando usted escribe sus funciones salmuera cargadoras/Saver (donde se llaman pickle.load()/ pickle.dump() para cargar/guardar la jerarquía de objetos/graph) do import _pickle as pickle para las mejores velocidades (_pickle es algo más rápido que C impl que generalmente es compatible con los requisitos de su aplicación).

Cuestiones relacionadas