前言

在 Python 中提供了一个用于拷贝操作的 copy 模块,该模块中提供 浅拷贝深拷贝 两种操作,其中:

  • 浅拷贝:只是将对象管理地址进行打包复制,其内部的元素的并未进行复制,而是使用旧的存储地址。
  • 深拷贝 :是将对象中的所有元素进行复制,然后重新开辟空间来存储。

对象和内存

对象和内存中的值是映射的关系,当需要取内存中的值的时候,需要通过其变量名去获取。

内存中的值是单一的,但其映射的对象可以是多个,所以某一个对象修改其内存的值后,其所有的映射到该内存上的对象都会刷新到最新的值。

实例如下:

>>> a = [1,2,3]    # 定义一个变量(对象)
>>>
>>> b = a    # 将变量的 a 的值赋给变量 b
>>> id(a)    # 查看 a 的存储内存空间
3070831436L
>>> id(b)    # 查看 b 的存储内存空间
3070831436L
>>>
>>> a.append(4)    # 给 a 对象列表,添加一个新的元素 ‘4’
>>> a    # 查看 a 的值
[1, 2, 3, 4]
>>> b    # 查看 b 的值
[1, 2, 3, 4]
>>>

通过以上可以看到,不同变量之间,相同的值存储的内存空间是一样的;当使用 a 变量修改其内容时,b 变量的值也会放生改变。

浅拷贝

特点:浅拷贝只复制变量的整体引用地址,不会复制变量内部元素的地址。当内部元素发生变化时,复制后的值和会随着赋值对象的变化而变化。

实例如下:

>>> import copy
>>> a = [1,2,['a','b'],3]    # 定义嵌套列表
>>> b = copy.copy( a )    # 复制a(浅拷贝)
>>> a
[1, 2, ['a', 'b'], 3]
>>> b
[1, 2, ['a', 'b'], 3]
>>> id(a)
3070610124L    # 查看 a 与 b 变量的地址
>>> id(b)
3070631500L

\#查看列表 a 与 b 中第 2 个元素的地址:

>>> id(a[1])
163477668
>>> id(b[1])
163477668

\#查看列表 a 与 b 中的第 3 个元素(嵌套列表)的地址:

>>> id(a[2])
3070631436L
>>> id(b[2])
3070631436L

#可见它们的地址还是同一个存储地址

\# 接下来是改变 a 的值,然后再查看 b 的值:

>>> a[2].append('c')
>>> a
[1, 2, ['a', 'b', 'c'], 3]
>>> b
[1, 2, ['a', 'b', 'c'], 3]

分析:通过观察可知 浅拷贝时,当改变元素内部的值时,复制后对象的值,会随着赋值前对象值的变化而变化。

由于数字类型为不可变类型,所以复制前后的存储位置是一致的,并不存在同值不同存储位置的情况。

因为 数字类型 为不可变类型,所以这里不加以比较!

提示:在大列表中 添加/修改 元素,复制后的值不受影响。

深拷贝

特点:深拷贝会将数据全部复制,然后重新开辟新的空间来储存该值。所以,复制后的值都是相对独立的,后期使用并不受复制前的对象所影响。

基本语法:

deepcopy(x, memo=None, _nil=[])

参数说明:x 是赋值的对象 、memo_nil 参数可缺省。

实例如下:

>>> import copy
>>> a = [4,5,['a','b'],6]
>>> b = copy.deepcopy(a) # 使用深拷贝复制 a 对象
>>> a
[4, 5, ['a', 'b'], 6]
>>> b
[4, 5, ['a', 'b'], 6]
>>>

\#查看列表 a 和 b 中的嵌套列表,可见它们的地址是独立的:

>>> id(a[2])
3070658220L
>>> id(b[2])
3069923596L

\# 修改 a 列表中的嵌套列表,观察其变化:

>>> a[2].append('c')
>>> a
[4, 5, ['a', 'b', 'c'], 6, 'c']
>>> b
[4, 5, ['a', 'b'], 6]

# 可见修改 a 后 b 也不会发生任何的变化

分析:通过以上可见,采用深拷贝操作后,是将被复制对象的所有值进行拷贝,然后重新开辟新的存储单元来存储拷贝后的内容,所以复制后的内容并不受前面被复制对象的改变而改变。

完整学习教程请访问Python3 入门教程——目录索引

最后修改:2022 年 06 月 08 日
如果觉得我的文章对你有用,请随意赞赏