Sự khác biệt giữa bản sao nông, bản sao sâu và hoạt động phân công bình thường là gì?


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

Tôi nhận được kết quả sau:

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

Nếu tôi thực hiện deepcopy:

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

kết quả giống nhau:

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

Nếu tôi làm việc trên các hoạt động chuyển nhượng:

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

thì kết quả là:

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

Ai đó có thể giải thích chính xác những gì làm cho một sự khác biệt giữa các bản sao? Nó có phải là một cái gì đó liên quan đến các đối tượng đột biến và bất biến? Nếu vậy, bạn có thể vui lòng giải thích cho tôi?

Câu trả lời:


364

Các hoạt động gán thông thường sẽ đơn giản chỉ hướng biến mới về phía đối tượng hiện có. Các tài liệu giải thích sự khác biệt giữa các bản sao nông và sâu:

Sự khác biệt giữa sao chép nông và sâu chỉ có liên quan đến các đối tượng ghép (các đối tượng có chứa các đối tượng khác, như danh sách hoặc thể hiện lớp):

  • Một bản sao nông xây dựng một đối tượng ghép mới và sau đó (trong phạm vi có thể) chèn các tham chiếu vào nó cho các đối tượng được tìm thấy trong bản gốc.

  • Một bản sao sâu xây dựng một đối tượng ghép mới và sau đó, đệ quy, chèn các bản sao vào đối tượng được tìm thấy trong bản gốc.

Đây là một minh chứng nhỏ:

import copy

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

Sử dụng các phép toán gán thông thường để sao chép:

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]

Sử dụng một bản sao nông:

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]

Sử dụng một bản sao sâu:

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

5
Assginment có giống như bản sao nông không?
deeshank

35
@Dshank Không. Một bản sao nông xây dựng một đối tượng mới, trong khi một nhiệm vụ sẽ chỉ đơn giản là trỏ biến mới vào đối tượng hiện có. Mọi thay đổi đối với đối tượng hiện tại sẽ ảnh hưởng đến cả hai biến (có gán).
grc

13
@grc "Mọi thay đổi đối với đối tượng hiện tại sẽ ảnh hưởng đến cả hai biến (có gán)" - câu lệnh này chỉ đúng với các đối tượng có thể thay đổi và không phải là loại bất biến như chuỗi, float, tuples.
Neerav

1
@grc Nhưng tôi đã cố gắng một ví dụ (tôi loại bỏ các dòng mới ở đây.) list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8] print(list_) print(newlist)Các newlisthiển thị vẫn [[1, 2], [3, 4]]. Nhưng list_[0]là một danh sách có thể thay đổi.
Alston

1
@Stallman list_[0]có thể thay đổi, nhưng bạn không biến đổi / sửa đổi nó. Hãy thử list_[0].append(9)hoặc list_[0][0] = 7thay vào đó.
grc

46

Đối với các đối tượng bất biến, không cần sao chép vì dữ liệu sẽ không bao giờ thay đổi, vì vậy Python sử dụng cùng một dữ liệu; id luôn giống nhau. Đối với các đối tượng có thể thay đổi, vì chúng có khả năng thay đổi, sao chép [nông] tạo ra một đối tượng mới.

Bản sao sâu có liên quan đến các cấu trúc lồng nhau. Nếu bạn có danh sách các danh sách, thì hãy phân tích sâu copiescác danh sách lồng nhau, vì vậy nó là một bản sao đệ quy. Chỉ cần sao chép, bạn có một danh sách bên ngoài mới, nhưng danh sách bên trong là tài liệu tham khảo.

Bài tập không sao chép. Nó chỉ đơn giản là đặt tham chiếu đến dữ liệu cũ. Vì vậy, bạn cần sao chép để tạo một danh sách mới có cùng nội dung.


With just copy, you have a new outer list but inner lists are references.Đối với các danh sách bên trong, một trong những bản sao sẽ bị ảnh hưởng bởi bản gốc? Tôi tạo một danh sách các danh sách như list_=[[1,2],[3,4]] newlist = list_.copy() list_[0]=[7,8]newlistvẫn giữ nguyên, vậy danh sách bên trong có phải là tài liệu tham khảo không?
Alston

1
@Stallman bạn không thay đổi danh sách được tham chiếu ở đây, chỉ cần tạo một danh sách mới và gán nó làm mục đầu tiên của một trong các bản sao. hãy thử làmlist_[0][0] = 7
perreal

20

Đối với các đối tượng không thay đổi, việc tạo một bản sao không có ý nghĩa nhiều vì chúng sẽ không thay đổi. Đối với các đối tượng đột biến assignment, copydeepcopyhành xử khác nhau. Hãy nói về mỗi người trong số họ với các ví dụ.

Một hoạt động gán chỉ đơn giản là gán tham chiếu của nguồn tới đích, ví dụ:

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

Bây giờ ijvề mặt kỹ thuật đề cập đến cùng một danh sách. Cả hai ijcó cùng một địa chỉ bộ nhớ. Bất kỳ cập nhật nào cho một trong hai sẽ được phản ánh cho người khác. ví dụ:

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

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

Mặt khác copydeepcopytạo một bản sao mới của biến. Vì vậy, bây giờ thay đổi đối với biến ban đầu sẽ không được phản ánh đến biến sao chép và ngược lại. Tuy nhiên copy(shallow copy), đừng tạo một bản sao của các đối tượng lồng nhau, thay vào đó nó chỉ sao chép tham chiếu của các đối tượng lồng nhau. Deepcopy sao chép tất cả các đối tượng lồng nhau đệ quy.

Một số ví dụ để chứng minh hành vi của copydeepcopy:

Ví dụ danh sách phẳng sử dụng 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

Ví dụ danh sách lồng nhau sử dụng 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

Ví dụ danh sách phẳng sử dụng 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

Ví dụ danh sách lồng nhau sử dụng 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    

18

Chúng ta hãy xem trong một ví dụ đồ họa về cách mã sau được thực thi:

import copy

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


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

nhập mô tả hình ảnh ở đây


5

a, b, c, d, a1, b1, c1 và d1 là các tham chiếu đến các đối tượng trong bộ nhớ, được xác định duy nhất bởi id của chúng.

Một hoạt động gán có một tham chiếu đến đối tượng trong bộ nhớ và gán tham chiếu đó cho một tên mới. c=[1,2,3,4]là một phép gán tạo một đối tượng danh sách mới chứa bốn số nguyên đó và gán tham chiếu cho đối tượng đó c. c1=clà một phép gán có cùng tham chiếu đến cùng một đối tượng và gán nó cho c1. Vì danh sách có thể thay đổi, nên mọi thứ xảy ra với danh sách đó sẽ hiển thị bất kể bạn truy cập nó thông qua chay c1vì cả hai đều tham chiếu cùng một đối tượng.

c1=copy.copy(c)là một "bản sao nông" tạo ra một danh sách mới và gán tham chiếu cho danh sách mới c1. cvẫn chỉ vào danh sách ban đầu. Vì vậy, nếu bạn sửa đổi danh sách tại c1, danh sách cđề cập đến sẽ không thay đổi.

Khái niệm sao chép không liên quan đến các đối tượng bất biến như số nguyên và chuỗi. Vì bạn không thể sửa đổi các đối tượng đó, không bao giờ cần phải có hai bản sao có cùng giá trị trong bộ nhớ tại các vị trí khác nhau. Vì vậy, số nguyên và chuỗi, và một số đối tượng khác mà khái niệm sao chép không áp dụng, chỉ được gán lại. Đây là lý do tại sao các ví dụ của bạn với abkết quả là id giống hệt nhau.

c1=copy.deepcopy(c)là một "bản sao sâu", nhưng nó hoạt động giống như một bản sao nông trong ví dụ này. Các bản sao sâu khác với các bản sao nông ở chỗ các bản sao nông sẽ tạo ra một bản sao mới của chính đối tượng, nhưng bất kỳ tài liệu tham khảo nào bên trong đối tượng đó sẽ không được sao chép. Trong ví dụ của bạn, danh sách của bạn chỉ có các số nguyên bên trong nó (không thay đổi được) và như đã thảo luận trước đây, không cần phải sao chép chúng. Vì vậy, phần "sâu" của bản sao sâu không áp dụng. Tuy nhiên, hãy xem xét danh sách phức tạp hơn này:

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

Đây là danh sách chứa các danh sách khác (bạn cũng có thể mô tả nó dưới dạng mảng hai chiều).

Nếu bạn chạy "bản sao nông" trên e, sao chép nó vào e1, bạn sẽ thấy rằng id của danh sách thay đổi, nhưng mỗi bản sao của danh sách chứa tham chiếu đến ba danh sách giống nhau - danh sách có số nguyên bên trong. Điều đó có nghĩa là nếu bạn phải làm e[0].append(3), thì esẽ được [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Nhưng e1cũng sẽ như vậy [[1, 2, 3],[4, 5, 6],[7, 8, 9]]. Mặt khác, nếu sau đó bạn đã làm e.append([10, 11, 12]), esẽ là [[1, 2, 3],[4, 5, 6],[7, 8, 9],[10, 11, 12]]. Nhưng e1vẫn sẽ[[1, 2, 3],[4, 5, 6],[7, 8, 9]] . Đó là bởi vì các danh sách bên ngoài là các đối tượng riêng biệt ban đầu, mỗi đối tượng chứa ba tham chiếu đến ba danh sách bên trong. Nếu bạn sửa đổi danh sách bên trong, bạn có thể thấy những thay đổi đó bất kể bạn đang xem chúng qua bản sao này hay bản khác. Nhưng nếu bạn sửa đổi một trong các danh sách bên ngoài như trên, thìechứa ba tham chiếu đến ba danh sách gốc cộng thêm một tham chiếu đến danh sách mới. Và e1vẫn chỉ chứa ba tài liệu tham khảo ban đầu.

Một 'bản sao sâu' sẽ không chỉ sao chép danh sách bên ngoài, mà còn đi vào bên trong danh sách và sao chép danh sách bên trong, để hai đối tượng kết quả không chứa bất kỳ tham chiếu nào giống nhau (liên quan đến các đối tượng có thể thay đổi) . Nếu các danh sách bên trong có thêm danh sách (hoặc các đối tượng khác như từ điển) bên trong chúng, chúng cũng sẽ bị trùng lặp. Đó là phần 'sâu' của 'bản sao sâu'.


2

Trong python, khi chúng ta gán các đối tượng như list, tuples, dict, v.v. cho một đối tượng khác thường có dấu '=', python tạo bản sao bằng cách tham chiếu . Đó là, giả sử chúng ta có một danh sách các danh sách như thế này:

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

và chúng tôi chỉ định một danh sách khác cho danh sách này như:

list2 = list1

sau đó nếu chúng ta in list2 trong thiết bị đầu cuối python, chúng ta sẽ nhận được điều này:

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

Cả list1 & list2 đều trỏ đến cùng một vị trí bộ nhớ, mọi thay đổi đối với bất kỳ một trong số chúng sẽ dẫn đến những thay đổi hiển thị trong cả hai đối tượng, tức là cả hai đối tượng đều trỏ đến cùng một vị trí bộ nhớ. Nếu chúng ta thay đổi list1 như thế này:

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

thì cả list1 và list2 sẽ là:

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

Bây giờ đến với bản sao Nông , khi hai đối tượng được sao chép qua bản sao nông, đối tượng con của cả hai đối tượng cha tham chiếu đến cùng một vị trí bộ nhớ nhưng mọi thay đổi mới trong bất kỳ đối tượng được sao chép nào sẽ độc lập với nhau. Hãy hiểu điều này với một ví dụ nhỏ. Giả sử chúng ta có đoạn mã nhỏ này:

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

chú ý, list2 vẫn không bị ảnh hưởng, nhưng nếu chúng ta thay đổi đối tượng con như:

list1[0][0] = 'x’

sau đó cả list1 và list2 sẽ được thay đổi:

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

Bây giờ, Deep copy giúp tạo ra các đối tượng hoàn toàn tách biệt với nhau. Nếu hai đối tượng được sao chép qua Deep Copy thì cả cha và con của nó sẽ được trỏ đến vị trí bộ nhớ khác nhau. Thí dụ :

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

chú ý, list2 vẫn không bị ảnh hưởng, nhưng nếu chúng ta thay đổi đối tượng con như:

list1[0][0] = 'x’

sau đó list2 sẽ không bị ảnh hưởng vì tất cả các đối tượng con và đối tượng cha trỏ đến vị trí bộ nhớ khác nhau:

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

Hy vọng nó giúp.


0

Mã bên dưới thể hiện sự khác biệt giữa gán, sao chép nông bằng cách sử dụng phương thức sao chép, sao chép nông bằng cách sử dụng (lát) [:] và độ sâu. Ví dụ dưới đây sử dụng các danh sách lồng nhau ở đó bằng cách làm cho sự khác biệt rõ ràng hơn.

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

0

GIST cần thực hiện là: Xử lý các danh sách nông (không có danh sách phụ, chỉ các yếu tố đơn lẻ) bằng cách sử dụng "phân công bình thường" làm tăng "hiệu ứng phụ" khi bạn tạo một danh sách nông và sau đó bạn tạo một bản sao của danh sách này bằng cách sử dụng "phân công bình thường" . "Hiệu ứng phụ" này là khi bạn thay đổi bất kỳ yếu tố nào trong danh sách sao chép được tạo, bởi vì nó sẽ tự động thay đổi các yếu tố tương tự của danh sách gốc. Đó là khicopy có ích, vì nó sẽ không thay đổi các thành phần danh sách ban đầu khi thay đổi các thành phần sao chép.

Mặt khác, copycũng có "tác dụng phụ", khi bạn có một danh sách có danh sách trong đó (danh sách phụ) và deepcopygiải quyết nó. Chẳng hạn, nếu bạn tạo một danh sách lớn có các danh sách lồng nhau trong đó (danh sách phụ) và bạn tạo một bản sao của danh sách lớn này (danh sách gốc). "Hiệu ứng phụ" sẽ phát sinh khi bạn sửa đổi danh sách phụ của danh sách sao chép sẽ tự động sửa đổi danh sách phụ của danh sách lớn. Đôi khi (trong một số dự án) bạn muốn giữ danh sách lớn (danh sách ban đầu của bạn) vì nó không có sửa đổi, và tất cả những gì bạn muốn là tạo một bản sao của các yếu tố của nó (danh sách phụ). Vì vậy, giải pháp của bạn là sử dụng deepcopysẽ xử lý "tác dụng phụ" này và tạo một bản sao mà không sửa đổi nội dung gốc.

Các hành vi copydeep copyhoạt động khác nhau chỉ liên quan đến các đối tượng hỗn hợp (ví dụ: các đối tượng có chứa các đối tượng khác như danh sách).

Dưới đây là những khác biệt được minh họa trong ví dụ mã đơn giản này:

Đầu tiên

hãy kiểm tra cách copyhành xử (nông), bằng cách tạo danh sách gốc và bản sao của danh sách này:

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

Bây giờ, hãy chạy một số printthử nghiệm và xem danh sách ban đầu hoạt động như thế nào so với danh sách sao chép của nó:

original_list và copy_list có địa chỉ khác nhau

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

các phần tử của original_list và copy_list có cùng địa chỉ

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

sub_elements của original_list và copy_list có cùng địa chỉ

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

sửa đổi các phần tử gốc_list KHÔNG sửa đổi các phần tử 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']]

sửa đổi các phần tử copy_list KHÔNG sửa đổi các phần tử gốc_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]

sửa đổi sub_elements gốc_list tự động sửa đổi 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]

sửa đổi copy_list sub_elements tự động sửa đổi sub_elements gốc_list

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]

Thứ hai

hãy kiểm tra cách deepcopyứng xử, bằng cách thực hiện tương tự như chúng tôi đã làm copy(tạo danh sách gốc và bản sao của danh sách này):

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

Bây giờ, hãy chạy một số printthử nghiệm và xem danh sách ban đầu hoạt động như thế nào so với danh sách sao chép của nó:

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

original_list và copy_list có địa chỉ khác nhau

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

các phần tử của original_list và copy_list có cùng địa chỉ

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

sub_elements của original_list và copy_list có địa chỉ khác nhau

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

sửa đổi các phần tử gốc_list KHÔNG sửa đổi các phần tử 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']]

sửa đổi các phần tử copy_list KHÔNG sửa đổi các phần tử gốc_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]

sửa đổi sub_elements gốc_list KHÔNG sửa đổi 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]

sửa đổi copy_list sub_elements KHÔNG sửa đổi sub_elements gốc_list

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]

0

Không chắc nó có được đề cập ở trên hay không, nhưng nó rất có thể nhập để hủy bỏ .copy () tạo tham chiếu đến đối tượng ban đầu. Nếu bạn thay đổi đối tượng sao chép - bạn thay đổi đối tượng ban đầu. .deepcopy () tạo đối tượng mới và sao chép thực sự đối tượng ban đầu sang đối tượng mới. Thay đổi đối tượng sâu mới không ảnh hưởng đến đối tượng ban đầu.

Và có, .deepcopy () sao chép đệ quy đối tượng gốc, trong khi .copy () tạo một đối tượng tham chiếu đến dữ liệu cấp đầu tiên của đối tượng gốc.

Vì vậy, sự khác biệt sao chép / tham chiếu giữa .copy () và .deepcopy () là đáng kể.


0

Bản sao sâu có liên quan đến các cấu trúc lồng nhau. Nếu bạn có danh sách các danh sách, thì bản sao sâu cũng sao chép các danh sách lồng nhau, vì vậy nó là một bản sao đệ quy. Chỉ cần sao chép, bạn có một danh sách bên ngoài mới, nhưng danh sách bên trong là tài liệu tham khảo. Bài tập không sao chép. Ví dụ

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

Ra ngoài

[[0, 1, 2, 3, 3], 4, 5] [[0, 1, 2, 3, 3], 4, 5, 3] Sao chép phương thức sao chép nội dung của danh sách bên ngoài vào danh sách mới nhưng danh sách bên trong là vẫn giống nhau cho cả hai danh sách, vì vậy nếu bạn thay đổi trong danh sách bên trong của bất kỳ danh sách nào, nó sẽ ảnh hưởng đến cả hai danh sách.

Nhưng nếu bạn sử dụng Deep copy thì nó cũng sẽ tạo một thể hiện mới cho danh sách bên trong.

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

Đầu ra

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


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

akhông phải là một bản đồ sâu của lst!
Georgy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.