• 13
  • 14
分享
  • python学习 - copy模块的浅复制与深复制
  • 鬼圣 2022-03-07 08:59:47 字数 5947 阅读 1775 收藏 14

简介

在使用列表或者字典进行传递参数的时候,可能会遇到函数改变了列表的值,但是不希望印象原来列表中的值,所以,python提供了copy模块,其中包含copy()和deepcopy()两函数,顾名思义copy()指的就是浅复制,deepcopy()指的就是深复制。

copy.copy()详解

copy.copy()主要是用来复制一维列表或者一维元组,即 像['A','B','C','D']这种,如果列表中再套列表,比如这种['A','B',['d','e','f'],'C'] 就不能进行复制更改。下面来做一个简单的测试。

import copy
lis_A = ['A','B','C','D']
lis_B = ['A','B',['d','e','f'],'C']
# 使用copy.copy()复制lis_A
copy_A = copy.copy(lis_A)
print('lis_A的值',  lis_A)
print('copy_A的值', copy_A)
# 打印出lis_A和copy_A的ID值
print('lis_A的ID值',  id(lis_A))
print('copy_A的ID值', id(copy_A))

输出结果是:

lis_A的值 ['A', 'B', 'C', 'D']
copy_A的值 ['A', 'B', 'C', 'D']
lis_A的ID值 1347357010368
copy_A的ID值 1347357613888

这里可以看出。copy_A的值与lis_A的值是一样的,但是它们的ID值是不一样的,说明copy_A指向了一个独立的列表。那么改变copy_A的值是不会去影响lis_A的列表的值,可以做试验:

# 改变copy_A的值,不影响lis_A的值
copy_A[1] = '改变B'

print('lis_A的值',  lis_A)
print('copy_A的值', copy_A)

# 打印出lis_A和copy_A的ID值
print('lis_A的ID值',  id(lis_A))
print('copy_A的ID值', id(copy_A))

输出结果:

lis_A的值 ['A', 'B', 'C', 'D']
copy_A的值 ['A', '改变B', 'C', 'D']
lis_A的ID值 1347357010368
copy_A的ID值 1347357613888

从上面可以看出,我改变了copy_A中的 'B' 的值,但是并没有影响到lis_A中的值。

使用copy()复制嵌套列表会是什么结果呢?

lis_B = ['A', 'B', ['d', 'e', 'f'], 'C']
# 使用copy_B复制 lis_B
copy_B = copy.copy(lis_B)
# 分别打印lis_B和copy_B的值
print('lis_B的值',  lis_B)
print('copy_B的值', copy_B)
# 打印出lis_B和copy_B的ID值
print('lis_B的ID值',  id(lis_B))
print('copy_B的ID值', id(copy_B))

输出的结果是:

lis_B的值 ['A', 'B', ['d', 'e', 'f'], 'C']
copy_B的值 ['A', 'B', ['d', 'e', 'f'], 'C']
lis_B的ID值 2116281195712
copy_B的ID值 2116321275968

咦,也复制出来了呀,怎么回事?别急,接着看,我们 改变一下copy_B中的 B 的值试试。

lis_B = ['A', 'B', ['d', 'e', 'f'], 'C']
# 使用copy_B复制 lis_B
copy_B = copy.copy(lis_B)
# 改变copy_B中的 B 的值
copy_B[1] = '改变B'
# 分别打印lis_B和copy_B的值
print('lis_B的值',  lis_B)
print('copy_B的值', copy_B)
# 打印出lis_B和copy_B的ID值
print('lis_B的ID值',  id(lis_B))
print('copy_B的ID值', id(copy_B))

输出结果:

lis_B的值 ['A', 'B', ['d', 'e', 'f'], 'C']
copy_B的值 ['A', '改变B', ['d', 'e', 'f'], 'C']
lis_B的ID值 2258614705408
copy_B的ID值 2258654720640

从上可以看出,copy_B中B的值已经被改变了,怎么回事?要翻车了吗?

我们再改变一下copy_B中的的整个列表试试?

lis_B = ['A', 'B', ['d', 'e', 'f'], 'C']
# 使用copy_B复制 lis_B
copy_B = copy.copy(lis_B)
# # 改变copy_B中的 B 的值
# copy_B[1] = '改变B'
# 改变lis_B中嵌套的列表 试试?
copy_B[2] = ['1', '2', '3']
# 分别打印lis_B和copy_B的值
print('lis_B的值', lis_B)
print('copy_B的值', copy_B)
# 打印出lis_B和copy_B的ID值
print('lis_B的ID值', id(lis_B))
print('copy_B的ID值', id(copy_B))

输出的结果是:

lis_B的值 ['A', 'B', ['d', 'e', 'f'], 'C']
copy_B的值 ['A', 'B', ['1', '2', '3'], 'C']
lis_B的ID值 1860576959872
copy_B的ID值 1860618301312

copy_B的列表也变了。在改变一下copy_B嵌套列表 ['1', '2', '3'] 中的‘2’的值呢?

lis_B = ['A', 'B', ['d', 'e', 'f'], 'C']
# 使用copy_B复制 lis_B
copy_B = copy.copy(lis_B)
# # 改变copy_B中的 B 的值
# copy_B[1] = '改变B'
# 改变lis_B中嵌套的列表 试试?
copy_B[2] = ['1', '2', '3']
# 改变lis_B中嵌套的列表中的值 试试?
copy_B[2][1] = '改变2'
# 分别打印lis_B和copy_B的值
print('lis_B的值', lis_B)
print('copy_B的值', copy_B)
# 打印出lis_B和copy_B的ID值
print('lis_B的ID值', id(lis_B))
print('copy_B的ID值', id(copy_B))

输出结果:

lis_B的值 ['A', 'B', ['d', 'e', 'f'], 'C']
copy_B的值 ['A', 'B', ['1', '改变2', '3'], 'C']
lis_B的ID值 2763457256768
copy_B的ID值 2763497140352

啊,‘2’也改变了,没有影响lis_B的值,怎么回事啊,翻车了吗?

我们直接改变复制出来的copy_B的嵌套列表的值,不先改变嵌套列表试试呢。

lis_B = ['A', 'B', ['d', 'e', 'f'], 'C']
# 使用copy_B复制 lis_B
copy_B = copy.copy(lis_B)
# # 改变copy_B中的 B 的值
# copy_B[1] = '改变B'
# # 改变lis_B中嵌套的列表 试试?
# copy_B[2] = ['1', '2', '3']
# # 改变lis_B中嵌套的列表中的值 试试?
# copy_B[2][1] = '改变2'
# 直接改变copy_B的值,将上两步注释掉,此时copy_B = lis_B = ['A', 'B', ['d', 'e', 'f'], 'C']
copy_B[2][1] = '改变2'  # 改变2 是改变 ['A', 'B', ['d', 'e', 'f'], 'C'] 中的 e
# 分别打印lis_B和copy_B的值
print('lis_B的值', lis_B)
print('copy_B的值', copy_B)
# 打印出lis_B和copy_B的ID值
print('lis_B的ID值', id(lis_B))
print('copy_B的ID值', id(copy_B))

输出结果:

lis_B的值 ['A', 'B', ['d', '改变2', 'f'], 'C']
copy_B的值 ['A', 'B', ['d', '改变2', 'f'], 'C']
lis_B的ID值 2342836779328
copy_B的ID值 2342878850496

神奇的一幕发生了,改变的是copy_B中的e的值,但是lis_B中e的值也发生了改变。

看懂了吗?这就是使用copy.copy()复制嵌套列表的弊端,表面看复制了lis_B[但是有没有完全复制 lis_B ,这种情况就要使用deepcopy()来进行复制。

但是,为什么之前的情况.为什么能将嵌套列表['d', 'e', 'f']改为['1', '2', '3'],再将['1', '2', '3']的 ‘2’ 变为 ‘改变2’呢。

(1)为什么能将  ['A', 'B', ['d', 'e', 'f'], 'C'] 变为 ['A', 'B', ['1', '2', '3'], 'C']?

简单理解,在整体改变['d', 'e', 'f'] 可以把他看做为一个整体,由X来代替,['1', '2', '3']由Y来代替。所以此时的变更相当于把['A', 'B', X, 'C'] 变更为 ['A', 'B', Y, 'C']。实际上变更的还是一维列表。copy.copy()是可以复制一维列表的。

(2)为什么 copy_B = ['A', 'B', ['d', 'e', 'f'], 'C'] 变为 ['A', 'B', ['1', '2', '3'], 'C'],再去变['1', '2', '3']中的‘2’时,不会影响lis_B =  ['A', 'B', ['d', 'e', 'f'], 'C']?

原因是第一步将 copy_B = ['A', 'B', ['d', 'e', 'f'], 'C'] 变为 ['A', 'B', ['1', '2', '3'], 'C'] 此时已经产生了一个新的列表 ['A', 'B', ['1', '2', '3'], 'C'] ,与列表 lis_B =  ['A', 'B', ['d', 'e', 'f'], 'C'] 是两个完全不相同的两个列表。自然不回影响。

如果说有个列表 lis_C = ['A', 'B', ['d', 'e', 'f'], ['x','y']],先变为 ['A', 'B', ['1', '2', '3'], ['x','y']],再去改变 'x'变会对源列表产生影响

# 定义一个lis_C
lis_C = ['A', 'B', ['d', 'e', 'f'], ['x', 'y']]
# 复制一个 copy_C
copy_C = copy.copy(lis_C)
# copy_C = ['A', 'B', ['d', 'e', 'f'], ['x', 'y']] 变为 ['A', 'B', ['1', '2', '3'], ['x', 'y']]
copy_C[2] = ['1', '2', '3']
# 在来改变 ['A', 'B', ['1', '2', '3'], ['x', 'y']] 中 'x'的值
copy_C[3][0] = '改变x'
# 分别打印copy_C和copy_C的值
print('lis_C的值', lis_C)
print('copy_C的值', copy_C)
# 打印出lis_C和copy_C的ID值
print('lis_C的ID值', id(lis_C))
print('copy_C的ID值', id(copy_C))

输出结果:

lis_C的值 ['A', 'B', ['d', 'e', 'f'], ['改变x', 'y']]
copy_C的值 ['A', 'B', ['1', '2', '3'], ['改变x', 'y']]
lis_C的ID值 2790729135616
copy_C的ID值 2790729135424

从可以看出,copy_C 中['d', 'e', 'f'] 变成[ '1', '2', '3']时,并不影响lis_C,在 将 ['x', 'y'] 变为 ['改变x', 'y']时就会印象lis_C

 copy.deepcopy()详解

上面说到,在使用copy.copy()复制嵌套的二维列表['A', 'B', ['d', 'e', 'f'], ['x', 'y']],然后改变嵌套列表中的值是,会影响到源列表的值,那么使用copy.deepcopy()是否会影响源列表呢?

import copy
# 定义一个lis_D
lis_D = ['A', 'B', ['d', 'e', 'f'], ['x', 'y']]
# 使用deepcopy()复制一个 copy_C
copy_D = copy.deepcopy(lis_D)
# 直接改变 copy_D 中嵌套列表 ['d', 'e', 'f'] 中的值d
copy_D[2][0] = '改变d'
# 分别打印copy_D和copy_D的值
print('lis_D的值', lis_D)
print('copy_D的值', copy_D)
# 打印出lis_D和copy_D的ID值
print('lis_D的ID值', id(lis_D))
print('copy_D的ID值', id(copy_D))

输出结果:

lis_D的值 ['A', 'B', ['d', 'e', 'f'], ['x', 'y']]
copy_D的值 ['A', 'B', ['改变d', 'e', 'f'], ['x', 'y']]
lis_D的ID值 2335362856512
copy_D的ID值 2335362856320

从上述结果可以很明显的看出,使用deepcopy()复制列表lis_之后,直接改变二维列表中的值 d,不会影响到源列表lis_D

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 1. 唯一索引比普通索引快吗,为什么唯一索引不一定比普通索引快, 还可能慢。查询时, 在未使用 limit 1 的情况下,在匹配到一条数据后,唯一索引即返回,普通索引会继续匹配下一条数据, 发现不匹配后返回。如此看来唯一索引少了一次匹配,但实际上这个消耗微乎其微。更新时,这个情况就比较复杂了。普通索引将记录放到 change buffer 中语句就执行完毕了。而对唯一索引而言,它必须要校验唯一性,因此,必须将数据页读入内存确定没有冲突,然后才能继续操作。对于写多读少的情况,普通索引利用 change buffer 有效减少了对磁盘的访问次数,因此普通索引性能要高于唯一索引。2. My...
            13 14 948
            分享
          • 我司是从2013年开始做接口自动化,那时候选用了测试接口工具--SoapUI。当时觉得非常好用,简单易上手,即使是代码小白,也能通过几次培训课,上手该工具。非常适用于代码基础薄弱,仅仅懂得业务的测试团队。随着业务的发展,一个项目的接口从几十个扩大到几百个,继续使用接口工具,无疑对后期脚本的维护产生了非常大的工作量。虽然说提供界面化管理,让做接口变的简单,但是却因为无法做接口分离,导致代码耦合性太高,大家都不愿意去维护老的接口。出现了老接口的case因为调试不通,而被无情删除的情况出现。事实上,只要接口仍然被软件调用的情况下,无论是老接口还是新接口。我们都是不能随意删除的。不然所谓的可持续集成,...
            0 0 853
            分享
          •   一、功能测试  1、点击提现按钮是否可以进入到提现界面;  2、未登录的情况下是否可以点击提现;  3、token失效或者登录态失效的情况下点击提现是否会跳到登录界面进行登录再提现;  4、假设提现的额度最低为0.01,最高为50000元,我需要通过边界值测试;  5、0.01能不能提现,100能不能提现,50000能不能提现,0.009能不能提现,50000.001能不能提现;  6、带小数点或者浮点型的能不能提现;  7、如果约束为小数点后2位、我用100.01能不能提现、我用100.009能不能提现成功;  8、是否有提现笔数的限制,比如一天只能提现10次,我要测试,提现10次,11...
            0 0 2384
            分享
          •   Part 01、  什么是数据质量管理   数据质量管理,是DAMA数据管理知识体系指南中数据治理领域非常重要的一部分(图1 所示),主要是指对数据从计划、获取、存储、共享、维护、应用、消亡生命周期的每个阶段里可能引发的各类数据质量问题,进行识别、度量、监控、预警等一列管理活动,并通过改善和提高组织的管理水平使得数据质量获得进一步提高。  Part 02、 数据质量问题原因及评价标准   数据在计划、获取、存储、共享、维护等各个环节都有可能引发数据质量问题,主要原因分为几下几个方面:  数据不完整:由于企业信息系统的孤立使用,各个业务系统或模块按照各自的需要录...
            0 0 883
            分享
          • 软件包含哪些内容数据 程序 文档软件生命周期需求分析概要设计详细设计编码测试验收瀑布模型计划需求分析设计编码测试运行-维护螺旋模型螺旋模型是一种演化软件开发过程模型,它兼顾了快速原型的迭代的特征以及瀑布模型的系统化与严格监控。测试流程获取测试需求编写测试计划指定测试方案开发于设计测试用例执行测试提交缺陷报告测试分析于评审提交测试总结准备下一版本测试软件测试过程模型V模型W模型H模型H模型适合外包测试公司 来一个需求用户需要提供软件,需求,设计,标准大型中上型的测试部门都是独立的优点早准备,早执行,效率高X模型X模型还定位了探索性测试,这是不进行事先计划的特殊类型的测试,这一方式往往能帮助有经验...
            0 0 4477
            分享
      • 51testing软件测试圈微信