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

谁能解释一下这些副本之间的区别是什么?它与可变和不可变对象有关吗?如果有,你能解释一下吗?


当前回答

不确定上面是否提到过,但理解.copy()创建对原始对象的引用是非常重要的。如果你改变了复制的对象-你改变了原始对象。 .deepcopy()创建新对象并真正复制原始对象到新对象。改变新的深度复制对象不会影响原始对象。

是的,.deepcopy()递归复制原始对象,而.copy()创建一个引用对象到原始对象的一级数据。

因此.copy()和.deepcopy()之间的复制/引用差异是显著的。

其他回答

深度复制与嵌套结构有关。如果你有列表的列表,那么deepcopy也复制嵌套的列表,所以它是递归复制。通过复制,您有一个新的外部列表,但内部列表是引用。赋值不复制。 为前

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

输出

[[0,1,2,3,3], 4,5] [[0,1,2,3,3], 4,5,3] 复制方法将外部列表的内容复制到新列表,但两个列表的内部列表仍然相同,因此如果你在任何列表的内部列表中做出更改,它将影响两个列表。

但是如果你使用深度复制,它也会为内部列表创建新的实例。

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

输出

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

在python中,当我们将list、tuples、dict等对象赋值给另一个对象时,通常使用' = '符号,python通过引用创建copy ' s。也就是说,我们有一个这样的列表:

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

然后我们给这个列表分配另一个列表,像这样:

list2 = list1

然后,如果我们在python终端中输出list2,我们将得到:

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

list1和list2都指向相同的内存位置,对其中任何一个的任何改变都会导致在两个对象中可见的变化,即两个对象都指向相同的内存位置。 如果我们像这样改变list1:

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

那么list1和list2都将是:

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

现在来看浅复制,当两个对象通过浅复制进行复制时,两个父对象的子对象引用相同的内存位置,但任何被复制对象的任何进一步的新更改都将彼此独立。 让我们通过一个小例子来理解这一点。假设我们有这样一小段代码:

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

注意,list2不受影响,但如果我们对子对象进行如下更改:

list1[0][0] = 'x’

那么list1和list2都将得到变化:

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

现在,深度复制有助于创建彼此完全隔离的对象。如果两个对象通过深度复制进行复制,那么父对象和子对象都将指向不同的内存位置。 例子:

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

注意,list2不受影响,但如果我们对子对象进行如下更改:

list1[0][0] = 'x’

list2也不会受到影响,因为所有子对象和父对象都指向不同的内存位置:

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

希望能有所帮助。

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

下面的代码显示了底层地址在复制、深度复制和赋值时是如何受到影响的。这类似于Sohaib Farooqi用列表展示的东西,但是用类。

from copy import deepcopy, copy

class A(object):
    """docstring for A"""
    def __init__(self):
        super().__init__()

class B(object):
    """docstring for B"""
    def __init__(self):
        super().__init__()
        self.myA = A()

a = B()
print("a is", a)
print("a.myA is", a.myA)
print("After copy")
b = copy(a)
print("b is", b)
print("b.myA is", b.myA)
b.myA = A()
print("-- after changing value")
print("a is", a)
print("a.myA is", a.myA)
print("b is", b)
print("b.myA is", b.myA)

print("Resetting")
print("*"*40)
a = B()
print("a is", a)
print("a.myA is", a.myA)
print("After deepcopy")
b = deepcopy(a)
print("b is", b)
print("b.myA is", b.myA)
b.myA = A()
print("-- after changing value")
print("a is", a)
print("a.myA is", a.myA)
print("b is", b)
print("b.myA is", b.myA)

print("Resetting")
print("*"*40)
a = B()
print("a is", a)
print("a.myA is", a.myA)
print("After assignment")
b = a
print("b is", b)
print("b.myA is", b.myA)
b.myA = A()
print("-- after changing value")
print("a is", a)
print("a.myA is", a.myA)
print("b is", b)
print("b.myA is", b.myA)

这段代码的输出如下:

a is <__main__.B object at 0x7f1d8ff59760>
a.myA is <__main__.A object at 0x7f1d8fe8f970>
After copy
b is <__main__.B object at 0x7f1d8fe43280>
b.myA is <__main__.A object at 0x7f1d8fe8f970>
-- after changing value
a is <__main__.B object at 0x7f1d8ff59760>
a.myA is <__main__.A object at 0x7f1d8fe8f970>
b is <__main__.B object at 0x7f1d8fe43280>
b.myA is <__main__.A object at 0x7f1d8fe85820>
Resetting
****************************************
a is <__main__.B object at 0x7f1d8fe85370>
a.myA is <__main__.A object at 0x7f1d8fe43310>
After deepcopy
b is <__main__.B object at 0x7f1d8fde3040>
b.myA is <__main__.A object at 0x7f1d8fde30d0>
-- after changing value
a is <__main__.B object at 0x7f1d8fe85370>
a.myA is <__main__.A object at 0x7f1d8fe43310>
b is <__main__.B object at 0x7f1d8fde3040>
b.myA is <__main__.A object at 0x7f1d8fe43280>
Resetting
****************************************
a is <__main__.B object at 0x7f1d8fe432b0>
a.myA is <__main__.A object at 0x7f1d8fe85820>
After assignment
b is <__main__.B object at 0x7f1d8fe432b0>
b.myA is <__main__.A object at 0x7f1d8fe85820>
-- after changing value
a is <__main__.B object at 0x7f1d8fe432b0>
a.myA is <__main__.A object at 0x7f1d8fe85370>
b is <__main__.B object at 0x7f1d8fe432b0>
b.myA is <__main__.A object at 0x7f1d8fe85370>

对于不可变对象,不需要复制,因为数据永远不会改变,所以Python使用相同的数据;id总是相同的。对于可变对象,因为它们可能会改变,[浅]复制创建一个新对象。

深度复制与嵌套结构有关。如果你有列表的列表,那么deepcopy也复制嵌套的列表,所以它是递归复制。通过复制,您有一个新的外部列表,但内部列表是引用。

赋值不复制。它只是将引用设置为旧数据。因此,您需要复制来创建一个具有相同内容的新列表。