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]])
输出验证了深拷贝的效果。
广告