В чем разница между мелким копированием, deepcopy и обычной операцией присваивания?
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))
Я получаю следующие результаты:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Если я выполню deepcopy:
a1 = copy.deepcopy(a)
b1 = copy.deepcopy(b)
c1 = copy.deepcopy(c)
d1 = copy.deepcopy(d)
результаты те же:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) False
mutable - id(d)==id(d1) False
Если я работаю над операциями присваивания:
a1 = a
b1 = b
c1 = c
d1 = d
тогда результаты будут следующими:
immutable - id(a)==id(a1) True
immutable - id(b)==id(b1) True
mutable - id(c)==id(c1) True
mutable - id(d)==id(d1) True
Кто-нибудь может объяснить, в чем именно разница между копиями? Это как-то связано с изменяемыми и неизменяемыми объектами? Если да, не могли бы вы, пожалуйста, объяснить мне это?
Переведено автоматически
Ответ 1
Обычные операции присваивания просто укажут новую переменную на существующий объект. В документах объясняется разница между мелким и глубоким копированием:
Разница между мелким и глубоким копированием актуальна только для составных объектов (объектов, которые содержат другие объекты, такие как списки или экземпляры классов):
Мелкое копирование создает новый составной объект, а затем (насколько это возможно) вставляет в него ссылки на объекты, найденные в оригинале.
Глубокая копия создает новый составной объект, а затем рекурсивно вставляет в него копии объектов, найденных в оригинале.
Вот небольшая демонстрация:
import copy
a = [1, 2, 3]
b = [4, 5, 6]
c = [a, b]
Использование обычных операций присваивания для копирования:
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]
Использование мелкого копирования:
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]
Using a deep copy:
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
Ответ 2
For immutable objects, there is no need for copying because the data will never change, so Python uses the same data; ids are always the same. For mutable objects, since they can potentially change, [shallow] copy creates a new object.
Deep copy is related to nested structures. If you have list of lists, then deepcopy copies
the nested lists also, so it is a recursive copy. With just copy, you have a new outer list, but inner lists are references.
Assignment does not copy. It simply sets the reference to the old data. So you need copy to create a new list with the same contents.
Ответ 3
For immutable objects, creating a copy doesn't make much sense since they are not going to change. For mutable objects, assignment
, copy
and deepcopy
behave differently. Let's talk about each of them with examples.
An assignment operation simply assigns the reference of source to destination, e.g:
>>> i = [1,2,3]
>>> j=i
>>> hex(id(i)), hex(id(j))
>>> ('0x10296f908', '0x10296f908') #Both addresses are identical
Now i
and j
technically refer to the same list. Both i
and j
have the same memory address. Any update to one
of them will be reflected in the other, 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
On the other hand, copy
and deepcopy
create a new copy of the variable. So now changes to the original variable will not be reflected
in the copy variable and vice versa. However, copy
(shallow copy) doesn't create a copy of nested objects, instead it just
copies the references to the nested objects, while deepcopy
(deep copy) copies all the nested objects recursively.
Some examples to demonstrate the behaviour of copy
and deepcopy
:
Flat list example using 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] #Update of original list didn't affect the copied variable
Nested list example using 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 the same address
>>> i[3].append(6)
>>> j
>>> [1,2,3,[4,5,6]] #Update of original nested list updated the copy as well
Flat list example using 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] #Update of original list didn't affect the copied variable
Nested list example using 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]] #Update of original nested list didn't affect the copied variable
Ответ 4