深度复制和浅复制的区别是什么?


当前回答

浅拷贝构造一个新的复合对象,并将其对原始对象的引用插入其中。

与浅拷贝不同,deepcopy构造新的复合对象,并插入原复合对象的原对象副本。

让我们举个例子。

import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)

上面的代码输出FALSE。

让我们看看怎么做。

原始复合对象x=[1,[2]](称为复合,因为它在对象中有对象(Inception))

如图所示,列表中有一个列表。

然后使用y = copy.copy(x)创建它的浅拷贝。python在这里所做的是,它将创建一个新的复合对象,但其中的对象指向原始对象。

在图像中,它为外层列表创建了一个新的副本。但内部列表与原始列表保持一致。

现在我们使用z = copy.deepcopy(x)创建它的深度复制。python在这里所做的是,它将为外部列表和内部列表创建新对象。如下图所示(红色高亮部分)。

最后代码输出False,因为y和z不是相同的对象。

HTH.

其他回答

我想给出一个例子,而不是正式的定义。

var originalObject = { 
    a : 1, 
    b : 2, 
    c : 3,
};

这段代码显示了一个浅拷贝:

var copyObject1 = originalObject;

console.log(copyObject1.a);         // it will print 1 
console.log(originalObject.a);       // it will also print 1 
copyObject1.a = 4; 
console.log(copyObject1.a);           //now it will print 4 
console.log(originalObject.a);       // now it will also print 4

var copyObject2 = Object.assign({}, originalObject);

console.log(copyObject2.a);        // it will print 1 
console.log(originalObject.a);      // it will also print 1 
copyObject2.a = 4; 
console.log(copyObject2.a);        // now it will print 4 
console.log(originalObject.a);      // now it will print 1

这段代码显示了一个深度拷贝:

var copyObject2 = Object.assign({}, originalObject);

console.log(copyObject2.a);        // it will print 1 
console.log(originalObject.a);      // it will also print 1 
copyObject2.a = 4; 
console.log(copyObject2.a);        // now it will print 4 
console.log(originalObject.a);      // !! now it will print 1 !!

简而言之,这取决于什么指向什么。在浅拷贝中,对象B指向对象a在内存中的位置。在深度复制中,对象A的内存位置中的所有东西都被复制到对象B的内存位置。

这篇wiki文章有一个很好的图表。

http://en.wikipedia.org/wiki/Object_copy

浅复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型——>,则执行字段的逐位复制;对于引用类型——>,引用被复制,但被引用的对象没有;因此,原始对象及其克隆对象引用同一个对象。

深度复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型——>,则执行字段的逐位复制。如果字段是引用类型——>,则执行引用对象的新副本。要克隆的类必须标记为[Serializable]。

除了上述所有定义之外,还有一个最常用的深度复制,位于类的复制构造函数(或重载赋值操作符)中。

浅复制——>是当你没有提供复制构造函数时。在这里,只复制对象,但不复制类的所有成员。

深度复制——>是当您决定在类中实现复制构造函数或重载赋值,并允许复制类的所有成员时。

MyClass& MyClass(const MyClass& obj) // copy constructor for MyClass
{
          // write your code, to copy all the members and return the new object
}
MyClass& operator=(const MyClass& obj) // overloading assignment operator,
{
          // write your code, to copy all the members and return the new object
}

为了避免混淆浅复制和简单地为list分配一个新变量名,再添加一点。

“假设我们有:

x = [
    [1,2,3],
    [4,5,6],
    ]

这个语句创建了3个列表:2个内部列表和一个外部列表。然后,外部列表的引用在名称x下可用

y = x

没有数据被复制。我们在内存的某个地方仍然有相同的3个列表。所有这一切所做的是使外部列表在名称y下可用,除了它之前的名称x

y = list(x)

or

y = x[:]

这将创建一个与x内容相同的新列表。列表x包含对两个内部列表的引用,因此新列表也将包含对这两个内部列表的引用。只复制了一个列表——外层列表。 现在内存中有4个列表,两个内部列表,一个外部列表,以及外部列表的副本。原始外部列表的名称为x,新的外部列表的名称为y。

内部列表没有被复制!此时,您可以从x或y访问和编辑内部列表!

如果你有一个二维(或更高)的列表,或者任何类型的嵌套数据结构,并且你想对所有内容进行完整复制,那么你想在复制模块中使用deepcopy()函数。你的解决方案也适用于2-D列表,迭代外部列表中的项目,并对每个项目进行复制,然后为所有内部副本构建一个新的外部列表。”

来源:https://www.reddit.com/r/learnpython/comments/1afldr/why_is_copying_a_list_so_damn_difficult_in_python/