W Pythonie struktura danych dict jest często używana do przechowywania zagnieżdżonych informacji. Programiści często spotykają się z koniecznością klonowania takich struktur podczas pracy z szablonami, konfiguracjami lub przekazywaniem danych między częściami aplikacji.
Standardowe kopiowanie dict za pomocą przypisania (=) tworzy jedynie odniesienie do oryginalnego obiektu. Powierzchowne kopiowanie (shallow copy) kopiuje sam obiekt dict, ale nie zagnieżdżone obiekty. Głębokie kopiowanie (deep copy) rekurencyjnie kopiuje wszystkie obiekty wewnątrz, co zapobiega wpływowi zmian w jednej kopii na drugą.
Do powierzchownego kopiowania można użyć dict.copy() lub konstruktora dict(), do głębokiego — moduł copy i funkcję deepcopy():
import copy d = {"a": 1, "b": {"c": 2}} shallow_d = d.copy() deep_d = copy.deepcopy(d) # Teraz zmiana shallow_d['b']['c'] wpłynie na d['b']['c'] # zmiana deep_d['b']['c'] nie wpłynie na oryginalny słownik
Kluczowe cechy:
Czy dict.copy() może kopiować zagnieżdżenia głębiej niż pierwszy poziom?
Nie, dict.copy() tworzy tylko powierzchowną kopię. Zagnieżdżone słowniki oraz tak czy owak będą odniesieniami do tych samych obiektów, co w oryginalnym dict.
Czy jeśli w strukturze jest obiekt niemutowalny (np. krotka), to czy deepcopy go głęboko skopiuje?
Deepcopy kopiuje tylko zmienne zagnieżdżone obiekty. Obiekty niemutowalne pozostają takie same — krotki, ciągi i liczby nie są kopiowane rekurencyjnie, a po prostu przenoszone do kopii.
Czy do głębokiego kopiowania można używać serializacji poprzez json.loads(json.dumps(dict))?
Można, ale z zastrzeżeniami. Taki sposób działa tylko dla serializowalnych typów i nie nadaje się, jeśli w słowniku znajdują się obiekty nieserializowalne (np. funkcje lub niestandardowe klasy):
import json orig = {"a": 10, "b": [1,2,3]} copy_like_deep = json.loads(json.dumps(orig)) # Nie działa dla złożonych obiektów
** Negatywny przypadek
Programista klonuje ustawienia za pomocą copy(), a następnie zmienia zagnieżdżoną wartość, sądząc, że to dwie niezależne struktury.
Zalety:
Proste i szybkie
Wady:
Zmiany w zagnieżdżonych obiektach w jednej kopii odzwierciedlają się we wszystkich — błędy trudne do debugowania.
** Pozytywny przypadek
Programista zawsze używa copy.deepcopy() dla zagnieżdżonych struktur, nawet jeśli oryginalny dict wydaje się płaski.
Zalety:
Gwarantowana niezależność danych, błędy zminimalizowane
Wady:
Deepcopy jest wolniejszy i zużywa więcej pamięci, czasami jest nadmiarowy.