Python中的浅拷贝和深拷贝操作


在Python中,变量只是一个对对象的引用。因此,当它被赋值给另一个变量时,它不会复制对象,而是充当对同一对象的另一个引用。这可以使用`id()`函数来验证。

>>> L1 = [1,2,3]
>>> L2 = L1
>>> id(L1), id(L2)
(2165544063496, 2165544063496)

上述代码的结果显示,两个列表对象的`id()`相同,这意味着它们都指向同一对象。L2被称为L1的浅拷贝。由于两者都指向同一对象,任何一个的更改都会反映在另一个对象中。

>>> L1 = [1,2,3]
>>> L2 = L1
>>> L2[1] = 100
>>> L1,L2
([1, 100, 3], [1, 100, 3])

在上面的例子中,L2中索引号为1的项已更改。我们看到此更改同时出现在两者中。

当创建一个全新的对象并进行复制操作时,嵌套对象的副本也会递归地添加到其中,则该副本被称为深拷贝。

Python标准库的`copy`模块提供了两种方法:

  • `copy.copy()` – 创建浅拷贝
  • `copy.deepcopy()` – 创建深拷贝

浅拷贝创建一个新对象并存储原始元素的引用,但不创建嵌套对象的副本。它只复制嵌套对象的引用。结果,复制过程不是递归的。

>>> import copy
>>> L1 = [[1,2,3], [4,5,6]]
>>> L2 = copy.copy(L1)
>>> L1,L2
([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]])
>>> L2.append([10,10,10])
>>> L1,L2
([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6], [10, 10, 10]])

这里L1是一个嵌套列表,L2是它的浅拷贝。虽然对父列表对象的引用被复制到L2中,但它的嵌套元素并没有被复制。因此,当我们将另一个列表添加到L2时,它不会反映在L1中。

但是,如果我们尝试修改子元素中的元素,其影响将在两个列表中都看到。

>>> L1 = [[1,2,3], [4,5,6]]
>>> L2 = copy.copy(L1)
>>> L1,L2
([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]])
>>> L2[1][0] = 100
>>> L1,L2
([[1, 2, 3], [100, 5, 6]], [[1, 2, 3], [100, 5, 6]])

然而,深拷贝创建一个新对象,并递归地添加原始元素中存在的嵌套对象的副本。

在下面的例子中,L2是L1的深拷贝。现在,如果我们更改内部列表的任何元素,这将不会显示在另一个列表中。

>>> L1 = [[1,2,3], [4,5,6]]
>>> L2 = copy.deepcopy(L1)
>>> L1,L2
([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [4, 5, 6]])
>>> L2[1][0] = 100
>>> L1,L2
([[1, 2, 3], [4, 5, 6]], [[1, 2, 3], [100, 5, 6]])

输出验证了深拷贝的效果。

更新于:2019年7月30日

457 次浏览

启动您的职业生涯

完成课程获得认证

开始学习
广告