To zależy od pożądanego zachowania klasy, które bierze pod uwagę decyzję o nadpisaniu (__copy__
lub __deepcopy__
).
W ogólnym copy.deepcopy
działa głównie poprawnie, to po prostu kopiuje wszystko (recursivly), więc wystarczy tylko zastąpić go, jeśli istnieje jakiś atrybut, który nie mogą być kopiowane (nigdy!).
Z drugiej strony należy zdefiniować __copy__
tylko wtedy, gdy użytkownicy (w tym ty) nie będą oczekiwać zmian, które będą propagować do skopiowanych instancji. Na przykład, jeśli po prostu owiniesz zmienny typ (np. list
) lub użyjesz typów zmiennych jako szczegółów implementacji.
Istnieje również przypadek, że minimalny zestaw atrybutów do skopiowania nie jest jasno zdefiniowany. W takim przypadku zastąpiłbym także __copy__
, ale może podniosę tam TypeError
i możliwe jest włączenie jednej (lub kilku) dedykowanych publicznych metod copy
.
Jednak moim zdaniem arr
liczy się jako szczegółów implementacji i dlatego chciałbym zastąpić __copy__
:
class T(object):
def __init__(self, x, y):
self.arr = [x, y]
def __copy__(self):
new = self.__class__(*self.arr)
# ... maybe other stuff
return new
Wystarczy, aby pokazać, że działa zgodnie z oczekiwaniami:
from copy import copy, deepcopy
x = T([2], [3])
y = copy(x)
x.arr is y.arr # False
x.arr[0] is y.arr[0] # True
x.arr[1] is y.arr[1] # True
x = T([2], [3])
y = deepcopy(x)
x.arr is y.arr # False
x.arr[0] is y.arr[0] # False
x.arr[1] is y.arr[1] # False
Wystarczy krótka notatka O oczekiwaniach:
Użytkownicy generalnie oczekują hat możesz przekazać instancję do konstruktora, aby utworzyć kopię minimalną (podobną lub identyczną do __copy__
). Na przykład:
lst1 = [1,2,3,4]
lst2 = list(lst1)
lst1 is lst2 # False
niektórych typów Pythona mają wyraźne copy
sposób, że (jeśli występuje) powinna zrobić to samo jak __copy__
. Które pozwoliłyby jednoznacznie przekazać w parametrach (choć nie widziałem w akcji jeszcze):
lst3 = lst1.copy() # python 3.x only (probably)
lst3 is lst1 # False
Jeśli klasa powinna być używana przez innych prawdopodobnie trzeba rozważyć te kwestie, jednak jeśli chcesz tylko do spraw, aby twoja klasa działała z copy.copy
, a następnie po prostu nadpisaj __copy__
.
Pojęcie "głęboki" pochodzi z części rekurencyjnej, w przeciwnym razie mówiąc "głęboka kopia tworzy nowy obiekt złożony, a następnie wstawia do niego głębokie kopie" będzie opisem rekurencyjnym. –