• 0
  • 0
分享
  • 不懂copy与deepcopy的区别?这一篇就够了!——软件测试圈
  • 曼倩诙谐 2022-11-08 13:29:46 字数 1846 阅读 1215 收藏 0

  2022年度软件测试行业的趋势预测:如果你也想了解更多发展趋势,那就点击下方链接填写调查问卷吧!助力测试行业发展,还能获得精美礼包哦~链接:http://vote.51testing.com/


  背景

  在运用Python进行开发代码过程中,会遇到变量复制备份的场景,但并没有得到预期的结果,例如下面的例子:

lista = ['a', 'b', [1, 2, 3]]
listb = lista.copy()
lista[2].append(4)
 
print(lista)  # ['a', 'b', [1, 2, 3, 4]]
print(listb)  # ['a', 'b', [1, 2, 3, 4]]

  代码本意是将lista复制给listb做个备份,再修改liasta,但是修改后发现listb也一并被修改了,没有达到备份的效果,这个是什么原因呢?

  存储方式

  首先了解一下Python的变量在内存中的存储方式。在基本数据类型中(包括set、list(tuple, str)、dict)都是采用引用的方式。

  也就是说,每个变量都存储的是这个变量的地址,而不是值本身,就算更复杂的嵌套结构,也是存储是每个元素的地址而已,用一幅图来表示。

1-1.png

  如上图所示,用户看到的是 lista的4个元素值,但是内存中保存的却是4个元素地址。

  当元素是列表时,第一层保存的是列表的地址,第二层保存的是列表元素的地址,第三层才是列表的值。当元素是字典的时候,与列表类似。

  列表的增删改

  在明白了变量存储方式后,继续看下内存下的增删改是怎么变化的。

  列表修改已有值

  新增一个内存块,再将引用的地址修改为新内存块的地址。

1-2.png

  列表新增一个值

  新增一个内存块,新增一个地址引用。

1-3.png

  列表整体重新赋值

  删除变量地址和引用的值,新增地址和引用值的内存块。

1-4.png

  copy与deepcopy的区别

  基于以上的理解,再来看两种copy的区别就会更容易理解了,首先记住一个原则:

  copy:不管多么复杂的数据结构,浅拷贝都只会copy一层。

  deepcopy:将整个变量内存全部复制一遍,新变量与原变量没有任何关系。

  举个例子来验证一下上面的结论:有如下的一段代码,最终的4个列表值是多少?

  注意:引用deepcopy需要导入copy库。

import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)
a.append(5)
a[1] = 20
a[4].append('c')
del a[0]
print(a)
print(b)
print(c)
print(d)

  列表b

  表示b也引用的a的地址,两者引用的内存地址是一样的。因此b和a的关系是紧密相连的,一模一样。可以通过 id(a) 和id(b)比较,两者是一样的。

  列表c

  由于c是浅拷贝的a列表,因此只copy了第一层,也就是地址层。

  所以,当a.append(5)时,新增了一个内存块,但是c只有前5个内存块,因此c没有变化。

  继续a修改了a[1],然而这个值是属于第一层,已经copy给了c,因此c也没有变化。

  继续a修改了子列表,这个时候a复制给c的只是列表的地址,且a中的子列表地址和c中的子列表地址是指向同一个地方的,因此修改了a中子列表,c中的子列表也会相应的改变。

  最后删除a[0],与修改a[1]一致,与c无关。可以用图再说明一下。

1-5.png

  列表d

  由于d是深拷贝的a列表,因此d是将a的地址和值一并复制过来,与a没有半点关系,也就是说d和a是两个完全独立的内存块,没有任何交集。因此,后面a的任意修改都与d无关,用图表示如下。

1-6.png

  因此,程序运行出来后的结果就是:

  a:[20,3,4,['a','b','c'],5]

  b:[20,3,4,['a','b','c'],5]

  c:[1,2,3,4,['a','b','c']]

  d:[1,2,3,4,['a','b']]

  总结

  综上,我们在使用copy的时候,一定要记住:copy只是拷贝了第一层,而deepcopy才是拷贝的全部数据。

  因此就不难发现,文章背景中的代码使用备份功能时,备份列表需要使用deepcopy,而不是简单的copy。




作者:王小健    

来源:http://www.51testing.com/html/20/n-7793720.html

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

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          • 简介在测试中,为了度量产品质量,代码覆盖率被作为一种测试结果的评判依据,在Python代码中用来分析代码覆盖率的工具当属Coverage。代码覆盖率是由特定的测试套件覆盖被测源代码的程度来度量,Coverage是一种用于统计Python代码覆盖率的工具,通过它可以检测测试代码的有效性,即测试case对被测代码的覆盖率几何。Coverage支不仅持分支覆盖率统计,还可以生成HTML/XML报告。并且XML报告可以结合Jenkins和Sonar集成工具一起使用。Coverage官方文档:http://coverage.readthedocs.org/en/latest/安装Coverage作为Py...
            0 0 3583
            分享
          • 昨天人民日报海外版的推文,着实引爆了互联网世界的 G 点,这么明显的故意勾搭 Google,还是头一次。其实 8 月 1 号的时候,有一家美媒就发文说谷歌可能会回归大陆,虽然后来被证实,这个报道的图片是盗用的,和新闻无关,所以消息的可信度也就大打折扣了,但就算这样,消息在国内 IT 圈仍然引起了不少的关注,有期待的,有不看好的,有等着看百度笑话的。我的主业是做测试,也算是技术人吧,所以我当时发了一条朋友圈,表达了自己的观点。但是很遗憾,我说的太隐晦,没人能看懂我要说的是什么(其实是人微言轻,没人关注)。其...
            1 1 2623
            分享
          • 本文所用到的案例:图一为登录首页,当输入用户名和密码后,点击【登录】按钮,如果用户名密码正确进入图三登录成功页面,否则弹出错误消息;点击【进行注册】按钮进入图二进行注册;点击【清除】按钮,清除数据库中的所有数据,这个按钮是为测试而临时设置的,正式产品中将会取消。图二为注册页,当输入用户名和密码后,点击【注册】按钮,当输入的用户名在数据库中不存在,注册成功,返回图一的登录页面,否则弹出错误消息。图三为登录成功页,当在图一中输入正确的用户名和密码后,进入这个页面,这里的"Hello world"将变为"Welcome "+用户名。正文部分谈起软件自动化测试,...
            0 1 2422
            分享
          • 可用性测试可用性测试是从用户的角度测试应用程序,以检查外观和用户友好性。例如,有一个用于股票交易的移动应用程序,并且测试人员正在执行可用性测试。测试人员可以检查该移动应用程序是否易于单手操作,滚动条应垂直,应用程序背景颜色应为黑色,价格和股票以红色或绿色显示的场景。此类应用程序可用性测试的主要思想是,用户一打开应用程序,用户就应该对市场有所了解。a) 探索性测试探索性测试是由测试团队执行的非正式测试。此测试的目的是探索应用程序并查找应用程序中存在的缺陷。测试人员使用业务领域的知识来测试应用程序。测试章程用于指导探索性测试。b) 跨浏览器测试跨浏览器测试是在不同的浏览器、操作系统、移动设备上测试...
            0 0 1246
            分享
          •   “测试自动化测试工程师可以将你从充满代码的世界中拯救出来。”     企业完全同意这一说法,这就是您在自动化测试行业中看到大量就业机会的原因。我在Quora上收到了很多与自动化测试中的职业选择相关的答案请求,以及人们如何在有或没有手动测试经验的情况下适应自动化测试。  在这里,我将详细解释成为测试自动化工程师的七个最重要的步骤。因此,所有希望将职业转向自动化测试的人都要注意所有这些。  1. 不要忽视手动测试  虽然我了解公司正在转向无代码自动化测试工具,达到专家级别并跟上行业自动化测试工程师的竞争,但最初要关注手动测试概念非常重要。  首先,我想强调使用手动和自动测试的事实。有...
            12 14 2153
            分享
      • 51testing软件测试圈微信