Jaka jest różnica między płytką kopią, głęboką kopią a normalną operacją przypisania?

210
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ć?

deeshank
źródło

Odpowiedzi:

364

Normalne operacje przypisania po prostu skierują nową zmienną w kierunku istniejącego obiektu. W docs wyjaśnić różnicę między płytkich i głębokich egzemplarzach:

Różnica między płytkim a głębokim kopiowaniem dotyczy tylko obiektów złożonych (obiektów zawierających inne obiekty, takie jak listy lub instancje klas):

  • Płytka kopia konstruuje nowy obiekt złożony, a następnie (w możliwym zakresie) wstawia do niego odwołania do obiektów znalezionych w oryginale.

  • Głęboka kopia konstruuje nowy obiekt złożony, a następnie rekurencyjnie wstawia do niego kopie obiektów znalezionych w oryginale.

Oto mała demonstracja:

import copy

a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]

Używanie normalnego przydziału działa do kopiowania:

d = c

print id(c) == id(d)          # True - d is the same object as c
print id(c[0]) == id(d[0])    # True - d[0] is the same object as c[0]

Używanie płytkiej kopii:

d = copy.copy(c)

print id(c) == id(d)          # False - d is now a new object
print id(c[0]) == id(d[0])    # True - d[0] is the same object as c[0]

Korzystanie z głębokiej kopii:

d = copy.deepcopy(c)

print id(c) == id(d)          # False - d is now a new object
print id(c[0]) == id(d[0])    # False - d[0] is now a new object
grc
źródło
5
czy przypisanie jest takie samo jak płytka kopia?
deeshank
35
@Dshank Nie. Płytka kopia konstruuje nowy obiekt, a przypisanie po prostu wskazuje nową zmienną na istniejący obiekt. Wszelkie zmiany istniejącego obiektu wpłyną na obie zmienne (z przypisaniem).
grc
13
@grc „Wszelkie zmiany istniejącego obiektu wpłyną na obie zmienne (z przypisaniem)” - to stwierdzenie jest prawdziwe tylko dla obiektów zmiennych, a nie niezmiennych typów, takich jak string, float, krotki.
Neerav
1
@grc Ale próbowałem przykład (usuwam tutaj nową linię). list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist)Obraz newlistnadal wyświetlany [[1, 2], [3, 4]]. Ale list_[0]lista jest zmienna.
Alston,
1
@Stallman list_[0]jest mutowalny , ale go nie mutujesz / nie modyfikujesz. Spróbuj list_[0].append(9)lub list_[0][0] = 7zamiast tego.
grc
46

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 copiesró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ą.

perreal
ź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 jak list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8]i newlistpozostaje taka sama, więc czy wewnętrzna lista jest referencją?
Alston,
1
@Stallman nie zmieniasz tutaj listy, do której się odwołujesz, po prostu tworzysz nową listę i przypisujesz ją jako pierwszy element jednej z kopii. spróbuj zrobićlist_[0][0] = 7
perreal
20

W przypadku obiektów niezmiennych tworzenie kopii nie ma większego sensu, ponieważ nie będą się zmieniać. Dla obiektów modyfikowalnych assignment, copyi deepcopyzachowuje się inaczej. Porozmawiajmy o każdym z nich z przykładami.

Operacja przypisania po prostu przypisuje odniesienie źródła do miejsca docelowego, np .:

>>> i = [1,2,3]
>>> j=i
>>> hex(id(i)), hex(id(j))
>>> ('0x10296f908', '0x10296f908') #Both addresses are identical

Teraz ii jtechnicznie odnosi się do tej samej listy. Zarówno ii jmają ten sam adres pamięci. Każda aktualizacja jednego z nich zostanie odzwierciedlona w drugim. na przykład:

>>> i.append(4)
>>> j
>>> [1,2,3,4] #Destination is updated

>>> j.append(5)
>>> i
>>> [1,2,3,4,5] #Source is updated

Z drugiej strony copyi deepcopytworzy nową kopię zmiennej. Tak więc teraz zmiany oryginalnej zmiennej nie będą odzwierciedlone w zmiennej kopiującej i odwrotnie. Jednak copy(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 copyi deepcopy:

Przykład płaskiej listy przy użyciu copy:

>>> import copy
>>> i = [1,2,3]
>>> j = copy.copy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different

>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable

Przykład listy zagnieżdżonej przy użyciu copy:

>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.copy(i)

>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different

>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x10296f908') #Nested lists have same address

>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5,6]] #Updation of original nested list updated the copy as well

Przykład płaskiej listy przy użyciu deepcopy:

>>> import copy
>>> i = [1,2,3]
>>> j = copy.deepcopy(i)
>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are different

>>> i.append(4)
>>> j
>>> [1,2,3] #Updation of original list didn't affected copied variable

Przykład listy zagnieżdżonej przy użyciu deepcopy:

>>> import copy
>>> i = [1,2,3,[4,5]]
>>> j = copy.deepcopy(i)

>>> hex(id(i)), hex(id(j))
>>> ('0x102b9b7c8', '0x102971cc8') #Both addresses are still different

>>> hex(id(i[3])), hex(id(j[3]))
>>> ('0x10296f908', '0x102b9b7c8') #Nested lists have different addresses

>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5]] #Updation of original nested list didn't affected the copied variable    
Sohaib Farooqi
źródło
18

Zobaczmy w graficznym przykładzie, w jaki sposób wykonuje się następujący kod:

import copy

class Foo(object):
    def __init__(self):
        pass


a = [Foo(), Foo()]
shallow = copy.copy(a)
deep = copy.deepcopy(a)

wprowadź opis zdjęcia tutaj

użytkownik1767754
źródło
5

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 obiektu c. c1=cto zadanie, które przyjmuje to samo odwołanie do tego samego obiektu i przypisuje je do c1. 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średnictwem club c1, 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 listy c1. cnadal wskazuje na oryginalną listę. Jeśli więc zmodyfikujesz listę w c1, lista, cdo 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 ai bidentyczne 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), ebyłoby [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Ale e1też by tak było [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Z drugiej strony, jeśli zrobiłbyś to później e.append([10, 11, 12]), ebyłoby [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]. Ale e1nadal 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, toezawiera trzy odniesienia do oryginalnych trzech list oraz jeszcze jedno odniesienie do nowej listy. I e1nadal 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”.

Andrew Gorcester
źródło
2

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ę:

list1 = [ [ 'a' , 'b' , 'c' ] , [ 'd' , 'e' , 'f' ]  ]

i do tej listy przypisujemy inną listę, na przykład:

list2 = list1

to jeśli wydrukujemy list2 w terminalu python, otrzymamy:

list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]

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:

list1[0][0] = 'x’
list1.append( [ 'g'] )

wówczas zarówno lista1, jak i lista2 będą:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g'] ]
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g’ ] ]

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:

import copy

list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]      # assigning a list
list2 = copy.copy(list1)       # shallow copy is done using copy function of copy module

list1.append ( [ 'g', 'h', 'i'] )   # appending another list to list1

print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]

zauważ, lista 2 pozostaje nienaruszona, ale jeśli wprowadzimy zmiany w obiektach potomnych, takich jak:

list1[0][0] = 'x’

wtedy zarówno lista1, jak i lista2 zostaną zmienione:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ] 
list2 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] ]

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:

import copy

list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f ']  ]         # assigning a list
list2 = deepcopy.copy(list1)       # deep copy is done using deepcopy function of copy module

list1.append ( [ 'g', 'h', 'i'] )   # appending another list to list1

print list1
list1 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ]
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f '] ]

zauważ, lista 2 pozostaje nienaruszona, ale jeśli wprowadzimy zmiany w obiektach potomnych, takich jak:

list1[0][0] = 'x’

wtedy lista 2 nie ulegnie zmianie, ponieważ wszystkie obiekty potomne i obiekt macierzysty wskazują na inną lokalizację pamięci:

list1 = [ [ 'x', 'b', 'c'] , [ 'd', 'e', ' f '] , [ 'g', 'h', 'i'] ] 
list2 = [ [ 'a', 'b', 'c'] , [ 'd', 'e', ' f  ' ] ]

Mam nadzieję, że to pomoże.

Nitish Chauhan
źródło
0

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.

from copy import deepcopy

########"List assignment (does not create a copy) ############
l1 = [1,2,3, [4,5,6], [7,8,9]]
l1_assigned = l1

print(l1)
print(l1_assigned)

print(id(l1), id(l1_assigned))
print(id(l1[3]), id(l1_assigned[3]))
print(id(l1[3][0]), id(l1_assigned[3][0]))

l1[3][0] = 100
l1.pop(4)
l1.remove(1)


print(l1)
print(l1_assigned)
print("###################################")

########"List copy using copy method (shallow copy)############

l2 = [1,2,3, [4,5,6], [7,8,9]]
l2_copy = l2.copy()

print(l2)
print(l2_copy)

print(id(l2), id(l2_copy))
print(id(l2[3]), id(l2_copy[3]))
print(id(l2[3][0]), id(l2_copy[3][0]))
l2[3][0] = 100
l2.pop(4)
l2.remove(1)


print(l2)
print(l2_copy)

print("###################################")

########"List copy using slice (shallow copy)############

l3 = [1,2,3, [4,5,6], [7,8,9]]
l3_slice = l3[:]

print(l3)
print(l3_slice)

print(id(l3), id(l3_slice))
print(id(l3[3]), id(l3_slice[3]))
print(id(l3[3][0]), id(l3_slice[3][0]))

l3[3][0] = 100
l3.pop(4)
l3.remove(1)


print(l3)
print(l3_slice)

print("###################################")

########"List copy using deepcopy ############

l4 = [1,2,3, [4,5,6], [7,8,9]]
l4_deep = deepcopy(l4)

print(l4)
print(l4_deep)

print(id(l4), id(l4_deep))
print(id(l4[3]), id(l4_deep[3]))
print(id(l4[3][0]), id(l4_deep[3][0]))

l4[3][0] = 100
l4.pop(4)
l4.remove(1)

print(l4)
print(l4_deep)
print("##########################")
print(l4[2], id(l4[2]))
print(l4_deep[3], id(l4_deep[3]))

print(l4[2][0], id(l4[2][0]))
print(l4_deep[3][0], id(l4_deep[3][0]))
Sandeep
źródło
0

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 copyprzydatne, ponieważ nie zmienia oryginalnych elementów listy podczas zmiany elementów kopiujących.

Z drugiej strony copyma również „efekt uboczny”, gdy masz listę, która zawiera listy (listy_list) i deepcopyrozwią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, deepcopyktóre zajmie się tym „efektem ubocznym” i wykona kopię bez modyfikowania oryginalnej treści.

Różne zachowania copyi deep copyoperacje 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ę copyzachowuje (płytki), tworząc oryginalną listę i kopię tej listy:

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)

Teraz uruchommy kilka printtestów i zobaczmy, jak zachowuje się oryginalna lista w porównaniu do listy kopii:

lista_oryginałów i lista_kopii ma różne adresy

print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328

elementy original_list i copy_list mają te same adresy

print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440

podelementy listy_oryginalnej i listy_kopii mają te same adresy

print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x1faef08 0x1faef08

modyfikowanie elementów original_list NIE modyfikuje elementów copy_list

original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]

modyfikowanie elementów copy_list NIE modyfikuje elementów original_list

copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]

modyfikowanie pod_elementów lista_oryginalna automatycznie modyfikuje pod_elementy lista_kopii

original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 7]

modyfikowanie pod_elementów lista_kopii automatycznie modyfikuje pod_elementy lista_oryginalnych

copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 7]

druga

sprawdźmy, jak się deepcopyzachowujemy, robiąc to samo co my copy(tworząc oryginalną listę i kopię tej listy):

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.copy(original_list)

Teraz uruchommy kilka printtestów i zobaczmy, jak zachowuje się oryginalna lista w porównaniu do listy kopii:

import copy
original_list = [1, 2, 3, 4, 5, ['a', 'b']]
copy_list = copy.deepcopy(original_list)

lista_oryginałów i lista_kopii ma różne adresy

print(hex(id(original_list)), hex(id(copy_list))) # 0x1fb3030 0x1fb3328

elementy original_list i copy_list mają te same adresy

print(hex(id(original_list[1])), hex(id(copy_list[1]))) # 0x537ed440 0x537ed440

podelementy listy_oryginalnej i listy_kopii mają różne adresy

print(hex(id(original_list[5])), hex(id(copy_list[5]))) # 0x24eef08 0x24f3300

modyfikowanie elementów original_list NIE modyfikuje elementów copy_list

original_list.append(6)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b']]

modyfikowanie elementów copy_list NIE modyfikuje elementów original_list

copy_list.append(7)
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]

modyfikowanie elementów podrzędnych lista_oryginalna NIE modyfikuje elementów podrzędnych lista_kopii

original_list[5].append('c')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b'], 7]

modyfikowanie podelementów lista_listy NIE modyfikuje podelementów lista_oryginalna

copy_list[5].append('d')
print("original_list is:", original_list) # original_list is: [1, 2, 3, 4, 5, ['a', 'b', 'c', 'd'], 6]
print("copy_list is:", copy_list) # copy_list is: [1, 2, 3, 4, 5, ['a', 'b', 'd'], 7]
Fouad Boukredine
źródło
0

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.

remort
źródło
0

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

import copy
spam = [[0, 1, 2, 3], 4, 5]
cheese = copy.copy(spam)
cheese.append(3)
cheese[0].append(3)
print(spam)
print(cheese)

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.

import copy
spam = [[0, 1, 2, 3], 4, 5]
cheese = copy.deepcopy(spam)
cheese.append(3)
cheese[0].append(3)
print(spam)
print(cheese)

Wynik

[0, 1, 2, 3] [[0, 1, 2, 3, 3], 4, 5, 3]

Shubham Agarwal
źródło
-1
>>lst=[1,2,3,4,5]

>>a=lst

>>b=lst[:]

>>> b
[1, 2, 3, 4, 5]

>>> a
[1, 2, 3, 4, 5]

>>> lst is b
False

>>> lst is a
True

>>> id(lst)
46263192

>>> id(a)
46263192 ------>  See here id of a and id of lst is same so its called deep copy and even boolean answer is true

>>> id(b)
46263512 ------>  See here id of b and id of lst is not same so its called shallow copy and even boolean answer is false although output looks same.
sudhir tataraju
źródło
anie jest głęboką kopią lst!
Georgy,