variable lista library example dict deepcopy python pickle deep-copy

python - lista - copy.deepcopy vs pickle



python deepcopy example (5)

Tengo una estructura de árbol de widgets, por ejemplo, la colección contiene modelos y el modelo contiene widgets. Quiero copiar toda la colección, copy.deepcopy es más rápido en comparación con ''pickle and de-pickle'' del objeto pero cPickle como está escrito en C es mucho más rápido, así que

  1. ¿Por qué no debería (nosotros) siempre usamos cPickle en lugar de deepcopy?
  2. ¿Hay alguna otra alternativa de copia? porque pickle es más lento que deepcopy pero cPickle es más rápido, por lo que puede ser una implementación en C de deepcopy será el ganador

Ejemplo de código de prueba:

import copy import pickle import cPickle class A(object): pass d = {} for i in range(1000): d[i] = A() def copy1(): return copy.deepcopy(d) def copy2(): return pickle.loads(pickle.dumps(d, -1)) def copy3(): return cPickle.loads(cPickle.dumps(d, -1))

Tiempos:

>python -m timeit -s "import c" "c.copy1()" 10 loops, best of 3: 46.3 msec per loop >python -m timeit -s "import c" "c.copy2()" 10 loops, best of 3: 93.3 msec per loop >python -m timeit -s "import c" "c.copy3()" 100 loops, best of 3: 17.1 msec per loop


Corto y algo tardío:

  • Si tiene que hacer clic en un objeto de todos modos, también puede usar el método cPickle para realizar una copia en profundidad (pero documentar)

Por ejemplo, usted podría considerar:

def mydeepcopy(obj): try: return cPickle.loads(cPickle.dumps(obj, -1)) except PicklingError: return deepcopy(obj)


Debería usar deepcopy porque hace que su código sea más legible. El uso de un mecanismo de serialización para copiar objetos en la memoria es, como mínimo, confuso para que otro desarrollador lea su código. El uso de deepcopy también significa que puede obtener los beneficios de futuras optimizaciones en deepcopy.

Primera regla de optimización: no lo hagas.


El problema es que pickle + unpickle puede ser más rápido (en la implementación de C) porque es menos general que la copia profunda: muchos objetos pueden ser copiados en profundidad pero no encurtidos. Supongamos, por ejemplo, que su clase A se cambió a ...

class A(object): class B(object): pass def __init__(self): self.b = self.B()

ahora, copy1 todavía funciona bien (la complejidad de A lo ralentiza pero no lo detiene); copy2 y copy3 break, el final del seguimiento de pila dice ...

File "./c.py", line 20, in copy3 return cPickle.loads(cPickle.dumps(d, -1)) PicklingError: Can''t pickle <class ''c.B''>: attribute lookup c.B failed

Es decir, el encurtido siempre asume que las clases y funciones son entidades de nivel superior en sus módulos, por lo que los escurre "por nombre": la copia profunda no hace absolutamente tales suposiciones.

Por lo tanto, si tiene una situación en la que la velocidad de "copia algo profunda" es absolutamente crucial, cada milisegundo es importante, y desea aprovechar las limitaciones especiales que SABE que se aplican a los objetos que está duplicando, como los que producen decapado. aplicables, o los que favorecen otras formas de serializaciones y otros accesos directos, por supuesto, adelante, pero si lo hace, DEBE estar consciente de que está obligando a su sistema a cumplir con esas limitaciones para siempre, y documente la decisión de diseño muy claramente. explícitamente en beneficio de futuros mantenedores.

Para el caso NORMAL, donde desea generalidad, use deepcopy ! -)


Incluso más rápido sería evitar la copia en primer lugar. Mencionas que estás haciendo rendering. ¿Por qué necesita copiar objetos?


No siempre es el caso que cPickle sea más rápido que deepcopy (). Si bien cPickle es probablemente siempre más rápido que pickle, si es más rápido que deepcopy depende de

  • el tamaño y nivel de anidamiento de las estructuras a copiar,
  • el tipo de objetos contenidos, y
  • El tamaño de la representación de la cadena en escabeche.

Si algo puede ser decapado, obviamente puede ser copiado en profundidad, pero lo contrario no es el caso: para encurtir algo, necesita ser completamente serializado ; Este no es el caso de la copia profunda. En particular, puede implementar __deepcopy__ muy eficientemente copiando una estructura en la memoria (piense en los tipos de extensión), sin poder guardar todo en el disco. (Piense en suspender a RAM frente a suspender en disco).

Un tipo de extensión bien conocido que cumple con las condiciones anteriores puede ser ndarray y, de hecho, sirve como un buen contraejemplo para su observación: con d = numpy.arange(100000000) , su código ofrece diferentes tiempos de ejecución:

In [1]: import copy, pickle, cPickle, numpy In [2]: d = numpy.arange(100000000) In [3]: %timeit pickle.loads(pickle.dumps(d, -1)) 1 loops, best of 3: 2.95 s per loop In [4]: %timeit cPickle.loads(cPickle.dumps(d, -1)) 1 loops, best of 3: 2.37 s per loop In [5]: %timeit copy.deepcopy(d) 1 loops, best of 3: 459 ms per loop

Si no se implementa __deepcopy__ , copy y copy_reg infraestructura común ( copy_reg módulo copy_reg , descrito en Relación entre decapado y copia profunda ).