2012-04-22 14 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 

Dlaczego deepcopy 15 razy wolniej niż copy?copy.copy vs wydajność copy.deepcopy na krotki

Każda funkcja musi powtarzać elementy krotki. Podczas tej iteracji copy tworzy kolejne odniesienie do każdego elementu; deepcopy deepcopies każdego elementu.

Ale każdy element to int, a jego głębsze odwzorowanie tworzy po prostu inne odniesienie do niego. Innymi słowy, te dwie funkcje wydają się wykonywać dokładnie te same kroki, tyle samo razy.

Oto weryfikacja że żadne nowe przypadki są tworzone w procesie:

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

Nie prawdziwą odpowiedź, ale podejrzenie: 'deepcopy' musi śledzić elementy, które zostały już skopiowane w celu umożliwienia odesłania cyklicznych, które może dodać trochę głową, szczególnie w takich prostych przypadkach. – Philipp

+0

Jeśli możesz rzucić własną kopię "deepcopy" może warto. Profilowałem jakiś ewolucyjny kod algorytmu i spędzałem mnóstwo czasu na pogłębianiu. Udało mi się ustalić ograniczenia wymagane dla algorytmu i napisać własną ograniczoną wersję deepcopy, która doprowadziła do znacznego przyspieszenia. Twój przebieg może się różnić. – Levon

Odpowiedz

6

Krotki są niezmienne, ale mogą zawierać zmienne elementy:

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

Należy pamiętać, że krotka nie zmienia : to jest ta lista; krotka nadal zawiera dokładnie tę samą listę.

deepcopy powtarza kopiowanie tych zmiennych elementów. copy po prostu kopiuje odniesienia do nich.

>>> 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

Tak, ale zarówno 'copy', jak i' deepcopy' potrzebują do iteracji elementów krotki. Gdy to robią, 'copy' tworzy kolejne odniesienie do każdego' int', podczas gdy 'deepcopy' kopiuje instancję' int'. Ale skopiowanie instancji 'int' po prostu zwraca inne odwołanie do tej samej instancji. Wygląda na to, że te dwie funkcje powinny wykonywać dokładnie te same kroki. Nie widzę, jak to skutkuje 15-krotnym wzrostem wydajności. – max

+1

Nie sądzę, że konieczne jest powtórzenie krotki dla płytkiego kopiowania. Nie wiedząc tak dużo o wewnętrznych Python, domyślam się, że połączenie memcpy powinno wystarczyć. –

+3

Masz rację, nie ma potrzeby powtarzania "kopii". Python nawet nie potrzebuje 'memcpy': może po prostu zwrócić inne odwołanie do oryginalnej krotki! Oczywiście to nie zadziała dla 'deepcopy'. – max