programowanieInżynier danych

Wyjaśnij różnicę między shallow copy (kopiowaniem płytkim) a deep copy (kopiowaniem głębokim), a także zachowaniem copy.copy i copy.deepcopy przy kopiowaniu złożonych obiektów. Podaj przykład, w którym nieprawidłowe zrozumienie prowadziło do błędu.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Kopia płytka (shallow copy) tworzy nowy obiekt na najwyższym poziomie, ale zagnieżdżone obiekty (elementy list, zagnieżdżone słowniki itd.) dzielą pamięć z oryginałem. Kopia głęboka (deep copy) rekurencyjnie kopiuje wszystkie poziomy obiektów.

Można używać przez moduł copy:

import copy original = [[1, 2], [3, 4]] shallow = copy.copy(original) deep = copy.deepcopy(original) shallow[0][0] = 99 # Zmienia i original, i shallow print(original) # [[99, 2], [3, 4]] # Teraz z deep original = [[1, 2], [3, 4]] deep = copy.deepcopy(original) deep[0][0] = 99 print(original) # [[1, 2], [3, 4]]

Cechy:

  • copy.copy(obj): kopiuje tylko "opakowanie"
  • copy.deepcopy(obj): pełna rekurencyjna kopia
  • Niektóre obiekty (np. otwarte pliki, gniazda) nie są kopiowane przez deep copy (wyjątek)

Pytanie z pułapką.

Co się stanie podczas kopiowania krotki, która zawiera obiekty zmienne?

Odpowiedź z przykładem:

tuple jest niezmienny, ale jego elementy mogą być zmienne (np. lista). Shallow copy i deep copy różnią się:

import copy t = ([1, 2], [3, 4]) shallow = copy.copy(t) deep = copy.deepcopy(t) shallow[0][0] = 99 print(t) # ([99, 2], [3, 4]) # Przy deep copy: t = ([1, 2], [3, 4]) deep = copy.deepcopy(t) deep[0][0] = 88 print(t) # ([1, 2], [3, 4])

Przykłady rzeczywistych błędów z powodu nieznajomości szczegółów tematu


Historia

W aplikacji do przetwarzania dokumentów dane przechowywano na liście wewnątrz słownika. Podczas kopiowania obiektów za pomocą copy.copy zagnieżdżone elementy przypadkowo zmieniały się podczas modyfikacji nowego obiektu. W rezultacie zmieniły się dane źródłowe w innych częściach systemu! Wystąpiła korupcja danych. Poprawiono to tylko poprzez zamianę na deepcopy.


Historia

W projekcie związanym z uczeniem maszynowym podczas zapisywania hiperparametrów modeli kopiowano listę konfiguracji przez standardowe przypisanie i shallow copy, po czym różne eksperymenty wzajemnie zmieniały swoje parametry. Źródło błędu znaleziono po diagnozowaniu zachowania kopiowania zagnieżdżonych list przez deepcopy.


Historia

W oprogramowaniu finansowym deep copy przypadkowo zastosowano do obiektu, który zawiera otwarty plik (handle), co spowodowało TypeError: cannot pickle '_io.TextIOWrapper' object — ponieważ copy.deepcopy używa pod maską pickle. Poprawiono to przez wyraźne przetwarzanie takich pól lub poprzez wywołanie shallow copy.