• 13
  • 14
分享
  • python学习 - copy模块的浅复制与深复制
  • 鬼圣 2022-03-07 08:59:47 字数 5947 阅读 1501 收藏 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

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

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   接口测试在我们的项目实施过程中有着重要的意义,快速实施接口测试能够让项目组更早地发现问题,降低修复成本,缩短产品周期。为了提高系统接口测试的效率,我们提早介入项目开发周期开展接口测试实践,并探索适合异步模式系统交易的接口自动化测试方案。  所谓的异步交易模式,即从接收交易到返回应答存在一定等待时间,且返回应答时另立连接至对手方。要实现该模式下接口测试自动化必须实现非实时报文的自动化匹配与结果核验。按照自动化设计思路,我们把“大象放进冰箱”需要三步操作,报文自动化拼装、解析回执和报文匹配、应答报文结果验证。  下面从这三个步骤介绍我们的接口自动化工具。  一、报文自动化拼装  首先对常规案例...
            0 0 997
            分享
          •   据报道,美国白宫上周五表示,使用特斯拉充电接口的电动汽车充电站有资格获得数十亿美元的美国联邦补贴,只要这些充电站也支持美国的标准充电接口CCS。  此前,美国汽车巨头福特和通用汽车分别宣布,将采用特斯拉的充电标准,即北美充电标准(NACS)。而白宫最新宣布的举措意味着,美国政府希望通过联邦补贴,推动行业转向有竞争关系的另一大充电标准CCS。  美国政府正在投资最多75亿美元,在美国最繁忙的高速公路上建设新的快速充电设备。这也是特斯拉首次与这个政府投资项目联系在一起。  受此消息影响,特斯拉股价上涨4.1%。分析师表示,福特和通用汽车宣布的决定是特斯拉的重大胜利,可能会使特斯拉的超级充电站成...
            0 0 540
            分享
          • 读者提问:『阿常你好,想请教一下,回归测试如何确定测试范围,如何避免遗漏 ?』阿常回答:三种方式,可以结合起来使用。1、产品 & 开发 助力产品提供需求覆盖的范围,开发指出代码修改涉及的模块。2、测试根据经验分析如果开发修改的是模块A,回归测试时就覆盖模块A,根据测试经验判断模块 B 关联了模块A,回归测试时就覆盖模块A和模块B。3、用例关联矩阵分析用例中标识与之关联的其他用例,回归测试时,此用例回归,与之关联的其他用例也回归;建立代码块和用例对应的矩阵,回归测试时,根据修改的代码块,找到对应的回归用例。阿常碎碎念:以上,12应该是企业中常见做法,3落地有些难度。看完今天的分...
            0 0 1154
            分享
          •   微软正在完善必应聊天,将单次会话提高到 10 条,每日上限 120 条之外,正在应用户需求添加新的功能和特性。  微软广告和网络服务主管 Mikhail Parakhin 会回复用户的推文中表示,现在用户呼声最高、要求最多的一个需求就是,保存和必应的聊天记录。从推文信息来看,微软内部正在推进该功能。  另一位用户咨询 Parakhin 是否会在语言方面有进一步的改进。IT之家翻译他的回复内容如下:“我们改进了匈牙利语等一些流行度不高的语言,接下来我们会不断改进本地化,下一个重点目标是希腊语”。作者:故渊原文链接:IT之家(ithome.com)
            0 0 510
            分享
          •   JMeter 是一个开源的负载测试工具,它可以模拟多种协议和应用程序的负载,包括 HTTP、FTP、SMTP、JMS、SOAP 和 JDBC 等。在进行接口自动化测试时,使用 JMeter 可以帮助我们快速地构建测试用例,模拟多种场景,发现接口的性能问题。下面是一些 JMeter 接口自动化测试的步骤和技巧。  步骤  第 1 步:创建测试计划  在 JMeter 中,测试计划是测试的最高级别,它包含了各种元素和配置,如线程组、断言、监听器等。测试人员需要在 JMeter 中创建一个新的测试计划,并添加必要的元素和配置。  要创建新的测试计划,请选择: 文件 > 新建 > 填写...
            0 0 311
            分享
      • 51testing软件测试圈微信