图解python中赋值、浅拷贝、深拷贝的区别

栏目: Python · 发布时间: 5年前

内容简介:Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果。下面本文就通过简单的例子介绍一下这些概念之间的差别。对象赋值直接看一段代码:

Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果。下面本文就通过简单的例子介绍一下这些概念之间的差别。

对象赋值

直接看一段代码:

will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = will
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
  
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

代码的输出为:

图解 <a href='https://www.codercto.com/topics/20097.html'>python</a> 中赋值、浅拷贝、深拷贝的区别

下面来分析一下这段代码:

  • 首先,创建了一个名为will的变量,这个变量指向一个list对象,从第一张图中可以看到所有对象的地址(每次运行,结果可能不同)

  • 然后,通过will变量对wilber变量进行赋值,那么wilber变量将指向will变量对应的对象(内存地址),也就是说”wilber is will”,”wilber[i] is will[i]”

可以理解为,Python中,对象的赋值都是进行对象引用(内存地址)传递

  • 第三张图中,由于will和wilber指向同一个对象,所以对will的任何修改都会体现在wilber上

这里需要注意的一点是,str是不可变类型,所以当修改的时候会替换旧的对象,产生一个新的地址39758496

图解python中赋值、浅拷贝、深拷贝的区别

浅拷贝

下面就来看看浅拷贝的结果:

import copy
  
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.copy(will)
  
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
  
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

代码结果为:

图解python中赋值、浅拷贝、深拷贝的区别

分析一下这段代码:

  • 首先,依然使用一个will变量,指向一个list类型的对象

  • 然后,通过copy模块里面的浅拷贝函数copy(),对will指向的对象进行浅拷贝,然后浅拷贝生成的新对象赋值给wilber变量

浅拷贝会创建一个新的对象,这个例子中”wilber is not will”

但是,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址),也就是说”wilber[i] is will[i]”

  • 当对will进行修改的时候

由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496

但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,所以will的修改结果会相应的反应到wilber上

图解python中赋值、浅拷贝、深拷贝的区别

总结一下,当我们使用下面的操作的时候,会产生浅拷贝的效果:

  • 使用切片[:]操作

  • 使用工厂函数(如list/dir/set)

  • 使用copy模块中的copy()函数

深拷贝

最后来看看深拷贝:

import copy
  
will = ["Will", 28, ["Python", "C#", "JavaScript"]]
wilber = copy.deepcopy(will)
  
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]
  
will[0] = "Wilber"
will[2].append("CSS")
print id(will)
print will
print [id(ele) for ele in will]
print id(wilber)
print wilber
print [id(ele) for ele in wilber]

代码的结果为:

图解python中赋值、浅拷贝、深拷贝的区别

分析一下这段代码:

  • 首先,同样使用一个will变量,指向一个list类型的对象

  • 然后,通过copy模块里面的深拷贝函数deepcopy(),对will指向的对象进行深拷贝,然后深拷贝生成的新对象赋值给wilber变量

跟浅拷贝类似,深拷贝也会创建一个新的对象,这个例子中”wilber is not will”

但是,对于对象中的元素,深拷贝都会重新生成一份(有特殊情况,下面会说明),而不是简单的使用原始元素的引用(内存地址)

例子中will的第三个元素指向39737304,而wilber的第三个元素是一个全新的对象39773088,也就是说,”wilber[2] is not will[2]”

  • 当对will进行修改的时候

由于list的第一个元素是不可变类型,所以will对应的list的第一个元素会使用一个新的对象39758496

但是list的第三个元素是一个可不类型,修改操作不会产生新的对象,但是由于”wilber[2] is not will[2]”,所以will的修改不会影响wilber

图解python中赋值、浅拷贝、深拷贝的区别

拷贝的特殊情况

其实,对于拷贝有一些特殊情况:

  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有拷贝这一说

也就是说,对于这些类型,”obj is copy.copy(obj)” 、”obj is copy.deepcopy(obj)”

如果元祖变量只包含原子类型对象,则不能深拷贝,看下面的例子

图解python中赋值、浅拷贝、深拷贝的区别

总结

本文介绍了对象的赋值和拷贝,以及它们之间的差异:

  • Python中对象的赋值都是进行对象引用(内存地址)传递

  • 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.

  • 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝

  • 对于非容器类型(如数字、字符串、和其他’原子’类型的对象)没有被拷贝一说

  • 如果元祖变量只包含原子类型对象,则不能深拷贝

觉得文章有用?立即:和朋友一起 共学习 共进步!

建议继续学习:

  1. 配置Nginx+uwsgi更方便地部署python应用    (阅读:104312)
  2. 如何成为Python高手    (阅读:50078)
  3. python实现自动登录discuz论坛    (阅读:30632)
  4. python编程细节──遍历dict的两种方法比较    (阅读:18229)
  5. 每个 程序员 都应该学习使用Python或Ruby    (阅读:15379)
  6. 我的PHP,Python和 Ruby 之路    (阅读:11019)
  7. 使用python爬虫抓站的一些技巧总结:进阶篇    (阅读:10821)
  8. 30分钟3300%性能提升――python+memcached网页优化小记    (阅读:10414)
  9. Python处理MP3的歌词和图片    (阅读:7545)
  10. 关于使用python开发web应用的几个库总结    (阅读:6813)

QQ技术交流群:445447336,欢迎加入!

扫一扫订阅我的微信号:IT技术博客大学习


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

敏捷软件开发

敏捷软件开发

马丁 / 邓辉、孙鸣 / 人民邮电出版社 / 2008-01-01 / 69.00元

《敏捷软件开发:原则模式和实践(C#版)》不仅是一部深入浅出、生动易懂的面向对象原则与设计模式著作。而且还是一部通俗的敏捷方法导引书和快速实用的LJML教程。通过《敏捷软件开发:原则模式和实践(C#版)》你会发现,许多以前看起来非常枯燥费解的概念,忽然间都豁然开朗。变得鲜活生动起来。 C#版与此前的Java版相比,主要的更新包括加强了UML的介绍章节。使其更加贴近实战;增加了对MVP模式的介......一起来看看 《敏捷软件开发》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器