import copy
a = "deepak"
b = 1, 2, 3, 4
c = [1, 2, 3, 4]
d = {1: 10, 2: 20, 3: 30}
a1 = copy.copy(a)
b1 = copy.copy(b)
c1 = copy.copy(c)
d1 = copy.copy(d)
print("immutable - id(a)==id(a1)", id(a) == id(a1))
print("immutable - id(b)==id(b1)", id(b) == id(b1))
print("mutable - id(c)==id(c1)", id(c) == id(c1))
print("mutable - id(d)==id(d1)", id(d) == id(d1))
Otrzymuję następujące wyniki:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Jeśli wykonam głęboką kopię:
a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)
wyniki są takie same:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Jeśli pracuję nad operacjami przydziału:
a1 = a
b1 = b
c1 = c
d1 = d
wyniki to:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True
Czy ktoś może wyjaśnić, co dokładnie odróżnia kopie? Czy jest to coś związanego ze zmiennymi i niezmiennymi obiektami? Jeśli tak, czy możesz mi to wyjaśnić?
źródło
list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist)
Obraznewlist
nadal wyświetlany[[1, 2], [3, 4]]
. Alelist_[0]
lista jest zmienna.list_[0]
jest mutowalny , ale go nie mutujesz / nie modyfikujesz. Spróbujlist_[0].append(9)
lublist_[0][0] = 7
zamiast tego.W przypadku obiektów niezmiennych nie ma potrzeby kopiowania, ponieważ dane nigdy się nie zmienią, dlatego Python używa tych samych danych; identyfikatory są zawsze takie same. W przypadku obiektów zmiennych, ponieważ mogą one potencjalnie ulec zmianie, [płytka] kopia tworzy nowy obiekt.
Głęboka kopia jest związana z zagnieżdżonymi strukturami. Jeśli masz listę list, skopiuj
copies
również zagnieżdżone listy, aby była to kopia rekurencyjna. Po prostu kopiuj masz nową listę zewnętrzną, ale listy wewnętrzne są referencjami.Zadanie nie jest kopiowane. Po prostu ustawia odwołanie do starych danych. Potrzebujesz kopii, aby utworzyć nową listę z tą samą zawartością.
źródło
With just copy, you have a new outer list but inner lists are references.
W przypadku list wewnętrznych czy na skopiowaną miałaby wpływ oryginalna? Tworzę listę takich jaklist_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8]
inewlist
pozostaje taka sama, więc czy wewnętrzna lista jest referencją?list_[0][0] = 7
W przypadku obiektów niezmiennych tworzenie kopii nie ma większego sensu, ponieważ nie będą się zmieniać. Dla obiektów modyfikowalnych
assignment
,copy
ideepcopy
zachowuje się inaczej. Porozmawiajmy o każdym z nich z przykładami.Operacja przypisania po prostu przypisuje odniesienie źródła do miejsca docelowego, np .:
Teraz
i
ij
technicznie odnosi się do tej samej listy. Zarównoi
ij
mają ten sam adres pamięci. Każda aktualizacja jednego z nich zostanie odzwierciedlona w drugim. na przykład:Z drugiej strony
copy
ideepcopy
tworzy nową kopię zmiennej. Tak więc teraz zmiany oryginalnej zmiennej nie będą odzwierciedlone w zmiennej kopiującej i odwrotnie. Jednakcopy(shallow copy)
nie tworzy kopii zagnieżdżonych obiektów, tylko kopiuje referencję zagnieżdżonych obiektów. Deepcopy kopiuje rekurencyjnie wszystkie zagnieżdżone obiekty.Kilka przykładów wykazujących zachowanie
copy
ideepcopy
:Przykład płaskiej listy przy użyciu
copy
:Przykład listy zagnieżdżonej przy użyciu
copy
:Przykład płaskiej listy przy użyciu
deepcopy
:Przykład listy zagnieżdżonej przy użyciu
deepcopy
:źródło
Zobaczmy w graficznym przykładzie, w jaki sposób wykonuje się następujący kod:
źródło
a, b, c, d, a1, b1, c1 i d1 są odwołaniami do obiektów w pamięci, które są jednoznacznie identyfikowane przez ich identyfikatory.
Operacja przypisania pobiera odwołanie do obiektu w pamięci i przypisuje to odwołanie do nowej nazwy.
c=[1,2,3,4]
to zadanie, które tworzy nowy obiekt listy zawierający te cztery liczby całkowite i przypisuje odwołanie do tego obiektuc
.c1=c
to zadanie, które przyjmuje to samo odwołanie do tego samego obiektu i przypisuje je doc1
. Ponieważ lista jest zmienna, wszystko, co stanie się na tej liście, będzie widoczne niezależnie od tego, czy uzyskasz do niej dostęp za pośrednictwemc
lubc1
, ponieważ oba odnoszą się do tego samego obiektu.c1=copy.copy(c)
to „płytka kopia”, która tworzy nową listę i przypisuje odwołanie do nowej listyc1
.c
nadal wskazuje na oryginalną listę. Jeśli więc zmodyfikujesz listę wc1
, lista,c
do której się odnosi, nie ulegnie zmianie.Koncepcja kopiowania jest nieistotna dla niezmiennych obiektów, takich jak liczby całkowite i łańcuchy. Ponieważ nie można modyfikować tych obiektów, nigdy nie ma potrzeby posiadania dwóch kopii tej samej wartości w pamięci w różnych lokalizacjach. Zatem liczby całkowite i łańcuchy oraz niektóre inne obiekty, do których nie ma zastosowania koncepcja kopiowania, są po prostu ponownie przypisywane. Właśnie dlatego twoje przykłady
a
ib
identyczne identyfikatory.c1=copy.deepcopy(c)
jest „głęboką kopią”, ale w tym przykładzie działa tak samo jak płytka kopia. Głębokie kopie różnią się od płytkich kopii, ponieważ płytkie kopie utworzą nową kopię samego obiektu, ale wszelkie odniesienia w tym obiekcie same nie zostaną skopiowane. W twoim przykładzie twoja lista zawiera tylko liczby całkowite (które są niezmienne), a jak już wspomniano, nie ma potrzeby ich kopiowania. Zatem „głęboka” część głębokiej kopii nie ma zastosowania. Rozważ jednak tę bardziej złożoną listę:e = [[1, 2],[4, 5, 6],[7, 8, 9]]
Jest to lista zawierająca inne listy (można ją również opisać jako tablicę dwuwymiarową).
Jeśli uruchomisz „płytką kopię”
e
, kopiując jąe1
, przekonasz się, że zmienia się identyfikator listy, ale każda kopia listy zawiera odniesienia do tych samych trzech list - list z liczbami całkowitymi w środku. Oznacza to, że gdybyś to zrobiłe[0].append(3)
,e
byłoby[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Alee1
też by tak było[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Z drugiej strony, jeśli zrobiłbyś to późnieje.append([10, 11, 12])
,e
byłoby[[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]
. Alee1
nadal tak będzie[[1, 2, 3],[4, 5, 6],[7, 8, 9]]
. Wynika to z faktu, że listy zewnętrzne są osobnymi obiektami, które początkowo zawierają trzy odwołania do trzech list wewnętrznych. Jeśli zmodyfikujesz wewnętrzne listy, możesz zobaczyć te zmiany bez względu na to, czy przeglądasz je przez jedną kopię, czy drugą. Ale jeśli zmodyfikujesz jedną z zewnętrznych list jak wyżej, toe
zawiera trzy odniesienia do oryginalnych trzech list oraz jeszcze jedno odniesienie do nowej listy. Ie1
nadal zawiera tylko oryginalne trzy odniesienia.„Głęboka kopia” nie tylko powieliłaby zewnętrzną listę, ale również wchodziłaby do wewnątrz list i duplikowała wewnętrzne listy, tak że dwa wynikowe obiekty nie zawierałyby tych samych odniesień (w przypadku obiektów zmiennych) . Gdyby listy wewnętrzne zawierały w sobie dalsze listy (lub inne obiekty, takie jak słowniki), one również zostałyby powielone. To „głęboka” część „głębokiej kopii”.
źródło
W Pythonie, gdy przypisujemy obiekty takie jak lista, krotki, dykta itp. Do innego obiektu, zwykle ze znakiem „=”, python tworzy kopie przez odniesienie . To znaczy, powiedzmy, że mamy taką listę:
i do tej listy przypisujemy inną listę, na przykład:
to jeśli wydrukujemy list2 w terminalu python, otrzymamy:
Zarówno lista1, jak i lista2 wskazują tę samą lokalizację pamięci, każda zmiana w dowolnej z nich spowoduje zmiany widoczne w obu obiektach, tj. Oba obiekty wskazują tę samą lokalizację pamięci. Jeśli zmienimy list1 w ten sposób:
wówczas zarówno lista1, jak i lista2 będą:
Przechodząc teraz do Płytkiej kopii , gdy dwa obiekty są kopiowane za pomocą płytkiej kopii, obiekt podrzędny obu obiektów nadrzędnych odnosi się do tej samej lokalizacji w pamięci, ale wszelkie dalsze nowe zmiany w dowolnym z kopiowanych obiektów będą od siebie niezależne. Rozumiemy to na małym przykładzie. Załóżmy, że mamy ten mały fragment kodu:
zauważ, lista 2 pozostaje nienaruszona, ale jeśli wprowadzimy zmiany w obiektach potomnych, takich jak:
wtedy zarówno lista1, jak i lista2 zostaną zmienione:
Teraz funkcja Głębokie kopiowanie pomaga tworzyć ze sobą całkowicie izolowane obiekty. Jeśli dwa obiekty zostaną skopiowane za pomocą funkcji głębokiego kopiowania, wówczas zarówno rodzic, jak i jego dziecko będą wskazywać inną lokalizację pamięci. Przykład:
zauważ, lista 2 pozostaje nienaruszona, ale jeśli wprowadzimy zmiany w obiektach potomnych, takich jak:
wtedy lista 2 nie ulegnie zmianie, ponieważ wszystkie obiekty potomne i obiekt macierzysty wskazują na inną lokalizację pamięci:
Mam nadzieję, że to pomoże.
źródło
Poniższy kod pokazuje różnicę między przypisaniem, płytką kopią przy użyciu metody kopiowania, płytką kopią przy użyciu (wycinka) [:] i głęboką kopią. Poniższy przykład wykorzystuje zagnieżdżone listy, czyniąc różnice bardziej widocznymi.
źródło
GIST do przyjęcia jest następujący: Radzenie sobie z płytkimi listami (bez pod_list, tylko pojedynczych elementów) za pomocą „normalnego przypisania” zwiększa „efekt uboczny” podczas tworzenia płytkiej listy, a następnie tworzysz kopię tej listy za pomocą „normalnego przypisania” . Ten „efekt uboczny” występuje, gdy zmienisz dowolny element utworzonej listy kopii, ponieważ automatycznie zmieni on te same elementy oryginalnej listy. Jest to
copy
przydatne, ponieważ nie zmienia oryginalnych elementów listy podczas zmiany elementów kopiujących.Z drugiej strony
copy
ma również „efekt uboczny”, gdy masz listę, która zawiera listy (listy_list) ideepcopy
rozwiązuje ją. Na przykład, jeśli utworzysz dużą listę, w której znajdują się zagnieżdżone listy (listy_list), i utworzysz kopię tej dużej listy (lista oryginalna). „Efekt uboczny” pojawiłby się, gdy zmodyfikujesz listy podrzędne listy kopii, która automatycznie zmodyfikuje listy podrzędne dużej listy. Czasami (w niektórych projektach) chcesz zachować dużą listę (oryginalną listę) bez zmian, a wszystko, czego potrzebujesz, to zrobić kopię jej elementów (listy_list). W tym celu Twoim rozwiązaniem jest użycie,deepcopy
które zajmie się tym „efektem ubocznym” i wykona kopię bez modyfikowania oryginalnej treści.Różne zachowania
copy
ideep copy
operacje dotyczą tylko obiektów złożonych (tj. Obiektów zawierających inne obiekty, takie jak listy).Oto różnice zilustrowane w tym prostym przykładzie kodu:
Pierwszy
sprawdźmy, jak się
copy
zachowuje (płytki), tworząc oryginalną listę i kopię tej listy:Teraz uruchommy kilka
print
testów i zobaczmy, jak zachowuje się oryginalna lista w porównaniu do listy kopii:lista_oryginałów i lista_kopii ma różne adresy
elementy original_list i copy_list mają te same adresy
podelementy listy_oryginalnej i listy_kopii mają te same adresy
modyfikowanie elementów original_list NIE modyfikuje elementów copy_list
modyfikowanie elementów copy_list NIE modyfikuje elementów original_list
modyfikowanie pod_elementów lista_oryginalna automatycznie modyfikuje pod_elementy lista_kopii
modyfikowanie pod_elementów lista_kopii automatycznie modyfikuje pod_elementy lista_oryginalnych
druga
sprawdźmy, jak się
deepcopy
zachowujemy, robiąc to samo co mycopy
(tworząc oryginalną listę i kopię tej listy):Teraz uruchommy kilka
print
testów i zobaczmy, jak zachowuje się oryginalna lista w porównaniu do listy kopii:lista_oryginałów i lista_kopii ma różne adresy
elementy original_list i copy_list mają te same adresy
podelementy listy_oryginalnej i listy_kopii mają różne adresy
modyfikowanie elementów original_list NIE modyfikuje elementów copy_list
modyfikowanie elementów copy_list NIE modyfikuje elementów original_list
modyfikowanie elementów podrzędnych lista_oryginalna NIE modyfikuje elementów podrzędnych lista_kopii
modyfikowanie podelementów lista_listy NIE modyfikuje podelementów lista_oryginalna
źródło
Nie jestem pewien, czy wspomniano powyżej, czy nie, ale bardzo łatwo jest zrozumieć, że .copy () tworzy odniesienie do oryginalnego obiektu. Jeśli zmienisz skopiowany obiekt - zmienisz oryginalny obiekt. .deepcopy () tworzy nowy obiekt i wykonuje prawdziwe kopiowanie oryginalnego obiektu na nowy. Zmiana nowego głęboko kopiowanego obiektu nie wpływa na oryginalny obiekt.
I tak, .deepcopy () kopiuje rekurencyjnie oryginalny obiekt, podczas gdy .copy () tworzy obiekt referencyjny do danych pierwszego poziomu oryginalnego obiektu.
Zatem różnica w kopiowaniu / odwoływaniu się między .copy () i .deepcopy () jest znacząca.
źródło
Głęboka kopia jest związana z zagnieżdżonymi strukturami. Jeśli masz listę list, wówczas kopiowanie głębokie kopiuje również listy zagnieżdżone, więc jest to kopia rekurencyjna. Po prostu kopiuj masz nową listę zewnętrzną, ale listy wewnętrzne są referencjami. Zadanie nie jest kopiowane. Dla np
Wynik
[[0, 1, 2, 3, 3], 4, 5] [[0, 1, 2, 3, 3], 4, 5, 3] Metoda kopiowania kopiuje zawartość listy zewnętrznej do nowej listy, ale lista wewnętrzna jest nadal są takie same dla obu list, więc jeśli wprowadzisz zmiany na wewnętrznej liście dowolnych list, wpłynie to na obie listy.
Ale jeśli użyjesz funkcji głębokiego kopiowania, utworzy ona również nową instancję dla wewnętrznej listy.
Wynik
[0, 1, 2, 3] [[0, 1, 2, 3, 3], 4, 5, 3]
źródło
źródło
a
nie jest głęboką kopiąlst
!