2012-04-22 12 views
5
%python -m timeit -s "import copy" "x = (1, 2, 3)" "copy.deepcopy(x)" 
100000 loops, best of 3: 10.1 usec per loop 

%python -m timeit -s "import copy" "x = (1, 2, 3)" "copy.copy(x)" 
1000000 loops, best of 3: 0.609 usec per loop 

Perché deepcopy 15 volte più lento di copy?copy.copy vs prestazioni copy.deepcopy su tuple

Ogni funzione deve scorrere tra gli elementi della tupla. Durante questa iterazione, copy crea un altro riferimento a ciascun elemento; deepcopy deepcopies ogni elemento.

Ma ogni elemento è un int e deepcopying un int crea semplicemente un altro riferimento ad esso. In altre parole, le due funzioni sembrano eseguire esattamente gli stessi passaggi, lo stesso numero di volte.

Ecco la verifica che nessuna nuova istanze vengono create nel processo:

ActivePython 3.2.1.2 (ActiveState Software Inc.) based on 
Python 3.2.1 (default, Jul 18 2011, 14:31:09) [MSC v.1500 64 bit (AMD64)] on win32 
Type "help", "copyright", "credits" or "license" for more information. 
>>> x = (1,2,3) 
>>> import copy 
>>> y = copy.copy(x) 
>>> z = copy.deepcopy(x) 
>>> x is y 
True 
>>> x is z 
True 
>>> x[1] is z[1] 
True 
+1

Non una vera risposta, ma un sospetto: 'deepcopy' ha bisogno di tenere traccia quali elementi si è già copiato per consentire i riferimenti ciclici, che potrebbe aggiungere un po 'in testa, soprattutto in questi casi semplici. – Philipp

+0

Se riesci a stampare la tua copia di "deepcopy", potrebbe valerne la pena. Stavo profilando un codice di algoritmo evolutivo e passavo molto tempo in deepcopy. Sono stato in grado di determinare i vincoli necessari per l'algoritmo e scrivere la mia versione limitata di deepcopy che ha portato ad una sostanziale accelerazione. Il tuo chilometraggio può variare. – Levon

risposta

6

tuple sono immutabili, ma possono contenere elementi mutevoli:

>>> a = (1, 2, []) 
>>> a[2].append(1000) 
>>> a 
(1, 2, [1000]) 

Si noti che la tupla non cambia : è la lista quella che fa; la tupla contiene ancora la stessa identica lista.

deepcopy dovrebbe ricorrere alla copia di quegli elementi mutabili. copy copia solo i riferimenti a loro.

>>> from copy import copy, deepcopy 

>>> a = (1, 2, []) 
>>> c = copy(a) 
>>> d = deepcopy(a) 

>>> a[2].append(1000) 

>>> c 
(1, 2, [1000]) 
>>> d 
(1, 2, []) 
+1

Sì, ma sia 'copia' che' deepcopy' devono scorrere gli elementi della tupla. Così facendo, 'copy' crea un altro riferimento a ogni' int', mentre 'deepcopy' copia l'istanza' int'. Ma copiare l'istanza 'int' restituisce semplicemente un altro riferimento alla stessa istanza. Sembra che le due funzioni dovrebbero fare esattamente gli stessi passi. Non vedo come questo si traduca in un successo di prestazioni 15x. – max

+1

Non penso sia necessario iterare sulla tupla per la copia superficiale. Senza sapere molto sugli interni di Python, direi che una chiamata memcpy dovrebbe essere sufficiente. –

+3

Hai ragione, non c'è bisogno di iterare per 'copia'. Python non ha nemmeno bisogno di 'memcpy': può solo restituire un altro riferimento alla tupla originale! Ovviamente, non funzionerà per 'deepcopy'. – max