【补充】深浅拷贝问题

发布时间 2023-07-25 16:13:23作者: Chimengmeng

【补充】深浅拷贝问题

【一】深浅拷贝问题引入

在Python中,深拷贝和浅拷贝是用于复制对象的两种不同的方式。

l = [1, 2, 3, [4, 5, 6, ]]
l2 = l
print(l2 is l)
# True
  • 通过
    • l2赋值为l
    • 实际上是将l2l指向相同的内存地址。
  • 所以
    • l2 is l的结果为True
    • 表示它们是同一个对象的两个引用。
  • 因此
    • l2l的修改都会影响到另一个。

(1)浅拷贝

from copy import copy

l3 = copy(l)
print(l3 is l)
# False

l3[3][1] = 999
print(l)
# [1, 2, 3, [4, 999, 6]]
print(l3)
# [1, 2, 3, [4, 999, 6]]
  • 使用copy()函数进行浅拷贝时
    • 创建了一个新的列表对象l3
      • 并复制了原始列表l中的元素。
    • 这意味着l3l是两个独立的对象
      • 分别指向不同的内存地址。
  • 然而,对于嵌套的可变对象(如列表)
    • 浅拷贝只会复制其引用
    • 而不会创建新的内存空间。
  • 因此,l3中的嵌套列表仍然指向相同的地址
    • 所以对l3中嵌套的列表进行修改
    • 也会影响到原始的列表l

(2)深拷贝

from copy import deepcopy

l4 = deepcopy(l)
l4[3][1] = 888
print(l)
# [1, 2, 3, [4, 5, 6]]
print(l4)
# [1, 2, 3, [4, 888, 6]]
  • 通过使用deepcopy()函数进行深拷贝
    • 会递归地复制嵌套对象,包括嵌套列表。
  • 这意味着在深拷贝操作中
    • 不仅会创建一个新的顶层列表对象l4
    • 还会创建一个新的嵌套列表对象
    • 其值与原始列表中的值相同。
  • 因此
    • 在对l4中的嵌套列表进行修改时
    • 并不会影响到原始的列表l
    • 它们指向不同的内存地址。

(3)小结

  • 综上所述
    • 浅拷贝只复制顶层对象
    • 而深拷贝会递归复制整个对象结构。
  • 在涉及到可变对象嵌套的情况下
    • 深拷贝是一种更安全的选项
    • 因为它可以确保对新对象的修改不会影响原始对象。

【二】深浅拷贝问题详解

  • 深拷贝和浅拷贝是常用的操作,它们在处理对象和数据结构时非常有用。
  • 让我们详细解释深拷贝和浅拷贝的概念,并结合案例进行演示。

(1)深拷贝:

  • 深拷贝是指创建一个新的对象,该对象与原始对象完全独立。
  • 换句话说,它会递归地复制所有嵌套对象,包括它们的内容,以便我们在修改新对象时不会影响到原始对象。
  • 下面是一个示例
    • 演示了如何使用copy模块中的deepcopy()函数进行深拷贝:
import copy

list1 = [1, 2, [3, 4]]
list2 = copy.deepcopy(list1)
  • 在这个例子中,我们创建了一个列表list1,其中包含一个嵌套列表。
  • 通过调用deepcopy()函数并将list1作为参数传递给它,我们可以创建一个名为list2的新对象,它是list1的深拷贝。
  • 现在,我们来演示深拷贝是如何避免原始对象的修改的:
list2[0] = 999
print(list1)  # 输出: [1, 2, [3, 4]]
print(list2)  # 输出: [999, 2, [3, 4]]
  • 可以看到,尽管我们修改了list2的第一个元素,但list1保持不变。
  • 这是因为list1list2是独立的对象,它们各自占用着不同的内存空间。

(2)浅拷贝:

  • 浅拷贝是指创建一个新对象,并将原始对象的元素复制到新对象中。
  • 然而
    • 如果原始对象包含可变的对象(如列表)
    • 则新对象中的这些元素仍然与原始对象中相应元素共享相同的内存地址。
  • 下面是一个示例
    • 演示了如何使用copy模块中的copy()函数进行浅拷贝:
import copy

list1 = [1, 2, [3, 4]]
list2 = copy.copy(list1)
  • 在这个例子中
    • 我们使用copy()函数创建了list1的浅拷贝list2
  • 让我们来看一下浅拷贝在修改可变对象时的行为:
list2[0] = 999
list2[2][0] = 777
print(list1)  # 输出: [1, 2, [777, 4]]
print(list2)  # 输出: [999, 2, [777, 4]]
  • 可以看到
    • 当我们修改list2中的第一个元素时
    • 只有list2受到影响
    • list1保持不变。
  • 但是
    • 当我们修改list2中嵌套列表的元素时
    • list1也会随之改变。
  • 这是因为浅拷贝只复制了列表的引用
    • 而没有创建新的内存空间来存储嵌套列表。

(3)综上所述

  • 深拷贝和浅拷贝在处理对象和数据结构时有不同的行为:

    • 深拷贝创建一个完全独立的对象,递归地复制所有嵌套对象。

    • 浅拷贝创建一个新对象,但它共享原始对象中可变对象的引用。