Care este diferența dintre copie superficială, deepcopy și normal misiune operație?

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))

Am obține următoarele rezultate:

immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False

Dacă am efectua deepcopy:

a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)

rezultatele sunt aceleași:

immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False

Dacă am lucra în misiune operațiuni:

a1 = a
b1 = b
c1 = c
d1 = d

apoi, rezultatele sunt:

immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True

Poate cineva sa explice ce anume face diferența între copii? Este ceva legat de mutabil & imuabil obiecte? Dacă este așa, poți te rog să-mi explici?

Soluția

Normal misiune operațiuni vor pur și simplu punctul de noua variabilă față de obiect existent. De documente să explice diferența între suprafață și adâncime copii:

diferența între suprafață și adâncime copierea este relevant doar pentru compus obiecte (obiecte care conțin alte obiecte, cum ar fi liste sau cazuri de clasă):

  • O copie superficială construiește un nou compus obiect și apoi (în măsura posibilului) inserează referințe de obiecte găsite în original.

  • O copie profundă construiește un nou compus obiect și apoi, recursiv, insertii de exemplare în ea obiectele găsite în original.

Aici's o mica demonstratie:

import copy

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

Folosind normal misiune operatings pentru a copia:

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]

Folosind o copie superficială:

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]

Folosind o copie profundă:

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
Comentarii (10)

Pentru imuabile obiecte, nu este nevoie pentru copierea deoarece datele nu se va schimba, astfel încât Python utilizează aceleași date; id-uri sunt întotdeauna aceleași. Pentru mutabil obiecte, deoarece acestea pot schimba, [superficială] copia creează un nou obiect.

Copie profundă este legată de structuri imbricate. Dacă aveți o listă de liste, apoi deepcopy copii de liste imbricate, de asemenea,, astfel încât acesta este un recursiv copie. Cu doar copia, ai o noua lista exterior, dar în interior sunt listele de referințe.

Cesiunea nu copia. Pur și simplu stabilește referire la datele vechi. Deci, ai nevoie de copie pentru a crea o listă nouă cu același conținut.

Comentarii (2)

Pentru imuabile obiecte, creând o copie don't face mai mult sens, deoarece acestea nu sunt de gând să se schimbe. Pentru obiecte mutabile assignment,copy și deepcopy se comportă diferit. Vă permite să vorbesc despre fiecare dintre ele cu exemple.

O misiune operațiune pur și simplu atribuie de referință de la sursă la destinație e.g:

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

Acum " i " și " j " din punct de vedere tehnic se referă la aceeași listă. Ambele " i " și " j " au aceeași adresă de memorie. Orice updation să fie dintre ele vor fi reflectate la alte. e.g:

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

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

Pe de altă parte, "copie" și deepcopy creează o nouă copie a variabilei. Deci, acum ca modificările să originale variabile nu vor fi reflectate pentru a copia variabilă și vice-versa. Cu toate acestea `copy(copie superficială), don't creează o copie de obiecte imbricate, în schimb, doar copii de referință de obiecte imbricate. Deepcopy copii de toate imbricate obiectele recursiv.

Câteva exemple pentru a demonstra comportamentul de "copie" și deepcopy:

Plat lista de exemplu, folosind "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

Listă imbricată exemplu, folosind "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

Listă plat exemplu, folosind 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

Listă imbricată exemplu, folosind 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    
Comentarii (0)

Las's a se vedea într-o grafică de exemplu cum este executat următorul cod:

import copy

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

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

Comentarii (0)

a, b, c, d, a1, b1, c1 și d1 sunt referințe la obiecte în memorie, care sunt identificate în mod unic de id-urile lor.

O misiune operațiunea durează o referință la obiect în memorie și atribuie această referință la un nume nou. c=[1,2,3,4] este o sarcină care creează o nouă listă a obiectelor care conțin cele patru numere întregi, și atribuie o referință la acest obiect a c. c1=c este o misiune care durează aceeași referință la același obiect și atribuie ca să c1. Deoarece lista este mutabil, tot ce se întâmplă la această listă vor fi vizibile indiferent dacă ai acces la ea prin " c " sau "c1", pentru că ambele referință la același obiect.

c1=copie.copia(c) e o "copie superficială", care creează o listă nouă și atribuie o referință la noua listă a c1. c se referă încă la lista inițială. Deci, dacă vă modifica lista de la "c1", lista pe care " c " se referă la nu se va schimba.

Conceptul de copiere este irelevant pentru imuabile obiecte, cum ar fi numere întregi și siruri de caractere. Deoarece puteți't modifica aceste obiecte, nu există niciodată o nevoie de a avea doi copii de aceeași valoare în memorie la locații diferite. Atât de numere întregi și siruri de caractere, și alte obiecte pentru care conceptul de copiere nu se aplică, sunt pur și simplu transferat. Acesta este motivul pentru exemple cu " a " și " b " rezultat identic id-uri.

c1=copie.deepcopy(c) e o "copie profundă", dar funcționează la fel ca o copie superficială în acest exemplu. Adânc copii diferă de la mică adâncime de exemplare în care superficială copii se va face o nouă copie a obiectului în sine, dar orice referințe interior acel obiect nu vor fi copiate. În exemplul tău, lista are doar numere întregi în interiorul acestuia (care sunt imuabile), și așa cum sa discutat anterior, nu este nevoie pentru a copia cele. Deci "profund" o parte din adânc copia nu se aplică. Cu toate acestea, ia în considerare acest lucru mai complex lista:

e = [[1, 2],[4, 5, 6],[7, 8, 9]]

Aceasta este o listă care conține alte liste (de asemenea, ai putea descrie ca un tablou bidimensional).

Dacă tu a alerga un "copie superficială" pe "e", copiindu-l la e1, veți găsi că id-ul din lista de schimbări, dar fiecare exemplar al listei conține referiri la aceleași trei liste-liste cu numere întregi în interior. Asta înseamnă că dacă ai de-a face e[0].append(3)", apoi " e ar fi[[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Dar e1 ar fi, de asemenea,[[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Pe de altă parte, dacă, ulterior, a făcut e.adăugați([10, 11, 12]), e ar fi[[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]. Dar e1 ar mai fi[[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Ca's pentru exterior listele sunt obiecte separate care, inițial, fiecare conține trei referințe la trei interioară liste. Dacă modificați interior liste, puteți vedea aceste schimbări, indiferent dacă vizualizați-le printr-un singur exemplar sau altul. Dar dacă modificați una din exterior liste ca mai sus, apoi " e " conține trei referiri la originalul trei liste, plus o trimitere mai mult la o nouă listă. Și e1 încă conține doar originalul trei referințe.

O 'copie profundă' ar nu numai duplicat exterior listă, dar, de asemenea, du-te în interiorul liste și duplicat interior liste, astfel încât cele două obiecte rezultate nu conțin aceleași referințe (în măsura în care mutabil obiecte sunt în cauză). Dacă interioară, listele au liste suplimentare (sau alte obiecte, cum ar fi dicționare) în interiorul lor, și ei vor fi duplicate. Ca'n 'profund' o parte din 'copie profundă'.

Comentarii (0)

În python, când ne-am atribui obiecte, cum ar fi liste, tupluri, dict, etc la un alt obiect, de obicei, cu o ' = ' semn, python creează copia e de referință. Asta este, să spunem că avem o lista de lista astfel :

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

și vom atribui o altă listă la această listă, cum ar fi :

list2 = list1

apoi, dacă ne-am imprima list2 în python terminal vom obține acest lucru :

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

Ambele list1 & list2 sunt orientate spre aceeași locație de memorie, orice schimbare la oricare le va duce la schimbări vizibile în ambele obiecte, am.e ambele obiecte sunt orientate spre aceeași locație de memorie. Dacă vom schimba list1 astfel :

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

apoi ambele list1 și list2 va fi :

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

Acum vin la copie Superficială, atunci când două obiecte sunt copiate prin intermediul copie superficială, copilul obiect de ambele părinte obiect se referă la aceeași locație de memorie dar nici noi modificări în orice obiect de copiat vor fi independente pentru fiecare alte. Să înțelegem acest lucru cu un mic exemplu. Să presupunem că avem acest mic fragment de cod :

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 '] ]

observați, list2 rămâne neafectat, dar dacă vom face modificări la obiectele copil, cum ar fi :

list1[0][0] = 'x’

apoi ambele list1 și list2 va schimba :

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

Acum, copie Profundă ajută la crearea complet obiecte izolate unul de celălalt. Dacă două obiecte sunt copiate prin intermediul Copie Profundă atunci ambele părinte & e copilul va fi îndreptat la diferite locație de memorie. Exemplu :

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 '] ]

observați, list2 rămâne neafectat, dar dacă vom face modificări la obiectele copil, cum ar fi :

list1[0][0] = 'x’

apoi, de asemenea, list2 vor fi afectate ca toate obiectele copil și părinte obiect de puncte la diferite locație de memorie :

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

Sper că vă ajută.

Comentarii (0)

Nu sunt sigur dacă este menționat mai sus sau nu, dar's foarte import pentru a înțelege asta .copy() a crea o referință la obiectul original. Dacă modificați obiect de copiat - ai schimba obiectul original. .deepcopy() creează un nou obiect și nu real copierea de obiectul original la unul nou. Schimbarea nouă deepcopied obiect nu't afecta obiectul original.

Și da, .deepcopy() exemplare originale obiect recursiv, în timp ce .copy() creeaza un obiect de referință la nivel de date de obiectul original.

Deci copierea/corelarea diferență între .copy() și .deepcopy() este semnificativă.

Comentarii (0)

Codul de mai jos demonstrează diferența între misiune, copie superficială, folosind metoda de copiere, copie superficială folosind (felie) [:] și deepcopy. Mai jos exemplu utilizează liste imbricate acolo făcând diferențe mai evidente.

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]))
Comentarii (0)

Ideea de a lua este aceasta: De-a face cu adâncime mică de liste (nu sub_lists, doar elemente unice), folosind "normal misiune" se ridică o "efect secundar" atunci când creați un superficial listă și apoi să creați o copie de pe această listă, folosind "normal misiune". Acest "efect secundar" este atunci când vă schimbați orice element din listă copie a creat, pentru că se va schimba în mod automat aceleași elemente de pe lista inițială. Aceasta este atunci când "copy" vine la îndemână, ca nu o't schimba original lista de elemente, atunci când schimbarea copia elemente.

Pe de altă parte, "copie" are o "efect secundar" la fel de bine, atunci când aveți o listă care are liste în ea (sub_lists), și deepcopy rezolvă. De exemplu, dacă creați o listă mare care are liste imbricate în acesta (sub_lists), și puteți crea o copie a acestui mare lista (lista inițială). "efect secundar" va apărea atunci când modificați sub_lists a copia lista care va modifica automat sub_lists de lista mare. Uneori (în anumite proiecte) pe care doriți să păstrați lista mare (lista inițială), așa cum este, fără modificări, și tot ce vreau este de a face o copie de elementele sale (sub_lists). Pentru că, soluția este de a utiliza deepcopy care va avea grijă de acest lucru "efect secundar" și de a face o copie fără a modifica conținutul original.

Diferite comportamente de `copy " și " copie profundă operațiuni se referă numai la obiectele compuse (de exemplu: obiecte care conțin alte obiecte, cum ar fi listele).

Aici sunt diferențele ilustrat în acest simplu exemplu de cod:

În primul rând

las's a verifica cât de "copie" (superficial) se comporta, de a crea o listă originală și o copie de pe această listă:

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

Acum, las's a rula unele "imprimare" teste și a vedea cât de lista inițială se comporte față de copia lista:

original_list și copy_list au adrese diferite

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

elemente de original_list și copy_list au aceleași adrese

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

sub_elements de original_list și copy_list au aceleași adrese

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

modificarea original_list elemente NU modifică copy_list elemente

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']]

modificarea copy_list elemente NU modifică original_list elemente

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]

modificarea original_list sub_elements modifica automat copy_list sub_elements

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]

modificarea copy_list sub_elements modifica automat original_list sub_elements

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]

Doua

las's a verifica ce deepcopy` se comporta, de a face același lucru, așa cum am făcut cu "copie" (a crea o listă originală și o copie a acestei liste):

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

Acum, las's a rula unele "imprimare" teste și a vedea cât de lista inițială se comporte față de copia lista:

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

original_list și copy_list au adrese diferite

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

elemente de original_list și copy_list au aceleași adrese

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

sub_elements de original_list și copy_list au adrese diferite

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

modificarea original_list elemente NU modifică copy_list elemente

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']]

modificarea copy_list elemente NU modifică original_list elemente

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]

modificarea original_list sub_elements NU modifică copy_list sub_elements

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]

modificarea copy_list sub_elements NU modifică original_list sub_elements

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]
Comentarii (0)
>>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.
Comentarii (1)