programowanieProgramista Backend Python

Jaka jest różnica między shallow copy a prostym przypisaniem zmiennej? Jak działa copy.copy() w odniesieniu do zagnieżdżonych struktur danych (listy w listach)?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

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 z podstępem

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

Przykłady rzeczywistych błędów z powodu braku wiedzy na temat tematu


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.