Przypisanie zmiennej (na przykład, a = b) w Pythonie nie kopiuje samego obiektu, a jedynie tworzy nową nazwę (odniesienie) do istniejącego obiektu. Zmiany w jednym odniesieniu będą widoczne w drugim, jeśli obiekt jest modyfikowalny.
Shallow copy (powierzchowne kopiowanie), na przykład za pomocą copy.copy(obj) lub wycinka [:] dla listy, tworzy nowy obiekt najwyższego poziomu, ale zagnieżdżone obiekty wewnątrz są kopiowane przez odniesienie (tzn. obie struktury "patrzą" na te same podkontenery). Jeśli zmieniać zagnieżdżone obiekty, zmiany będą widoczne przez oba obiekty.
Przykład:
import copy lst1 = [[1,2], [3,4]] lst2 = copy.copy(lst1) # lub lst1[:] lst1[0][0] = 100 print(lst2) # [[100, 2], [3, 4]]
lst2 to nowa lista, ale jej pierwszy element to ta sama zagnieżdżona lista.
Pytanie: Czym różni się lst2 = lst1[:] i lst2 = copy.copy(lst1)?
Odpowiedź: W praktyce dla zwykłych (jednowarstwowych) list nie ma różnic — obie metody wykonują powierzchowną kopię listy. Jednak dla niestandardowych klas kontenerowych może wystąpić różne zachowanie (na przykład, jeśli została zaimplementowana własna metoda __copy__). Podobnie dla innych typów (dict, set itd.) bezpieczniej jest używać wyspecjalizowanego modułu copy.
import copy lst1 = [1, 2, 3] lst2 = lst1[:] lst3 = copy.copy(lst1) print(lst2 == lst3) # True
Historia
W projekcie zajmującym się przetwarzaniem konfiguracji programista dublował domyślne parametry przez przypisanie params = default_params i liczył, że będzie je mógł zmieniać "izolowanie". W efekcie wszelkie zmiany w jakiejkolwiek kopii prowadziły do kaskady zmian we wszystkich częściach aplikacji, ponieważ w rzeczywistości pracował z jednym obiektem.
Historia
Niedoświadczony programista użył powierzchownej kopii listy do przechowywania stanu gry (game_states = states[:]). Przy złożonej strukturze (listy figur na planszy) zmiany w jednym stanie "przechodziły" do innych, łamiąc historię cofania i powtórzeń ruchów.
Historia
Przy próbie klonowania danych w aplikacji OOP wybór stanął między wycinkiem a copy.copy(). Ale w strukturze napotkano swoją klasę z własną metodą copy, która była uwzględniona tylko podczas użycia copy.copy(). Wycinek zignorował logikę kopiowania obiektu, a to doprowadziło do nieoczywistych błędów.