Python FAQ2:赋值、浅拷贝、深拷贝的区别?
在Python编程过程中,经常会遇到对象的拷贝,如果不理解浅拷贝和深拷贝的概念,你的代码就可能出现一些问题。所以,在这里按个人的理解谈谈它们之间的区别。
一、赋值(assignment)
在《Python FAQ1》一文中,对赋值已经讲的很清楚了,关键要理解变量与对象的关系。
>>> a = [1, 2, 3]
>>> b = a
>>> print(id(a), id(b), sep='\n')
139701469405552
139701469405552
在Python中,用一个变量给另一个变量赋值,其实就是给当前内存中的对象增加一个“标签”而已。
如上例,通过使用内置函数 id() ,可以看出 a 和 b 指向内存中同一个对象。a is b会返回 True 。
二、浅拷贝(shallow copy)
注意:浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
所谓“浅拷贝”,是指创建一个新的对象,其内容是原对象中元素的引用。(拷贝组合对象,不拷贝子对象)
常见的浅拷贝有:切片操作、工厂函数、对象的copy()方法、copy模块中的copy函数。
>>> a = [1, 2, 3]
>>> b = list(a)
>>> print(id(a), id(b)) # a和b身份不同
140601785066200 140601784764968
>>> for x, y in zip(a, b): # 但它们包含的子对象身份相同
... print(id(x), id(y))
...
140601911441984 140601911441984
140601911442016 140601911442016
140601911442048 140601911442048
从上面可以明显的看出来,a 浅拷贝得到 b,a 和 b 指向内存中不同的 list 对象,但它们的元素却指向相同的
int 对象。这就是浅拷贝!
三、深拷贝(deep copy)
所谓“深拷贝”,是指创建一个新的对象,然后递归的拷贝原对象所包含的子对象。深拷贝出来的对象与原对象没有任何关联。
深拷贝只有一种方式:copy模块中的deepcopy函数。
>>> import copy
>>> a = [1, 2, 3]
>>> b = copy.deepcopy(a)
>>> print(id(a), id(b))
140601785065840 140601785066200
>>> for x, y in zip(a, b):
... print(id(x), id(y))
...
140601911441984 140601911441984
140601911442016 140601911442016
140601911442048 140601911442048
看了上面的例子,有人可能会疑惑:
为什么使用了深拷贝,a和b中元素的id还是一样呢?
答:这是因为对于不可变对象,当需要一个新的对象时,python可能会返回已经存在的某个类型和值都一致的对象的引用。而且这种机制并不会影响 a 和 b 的相互独立性,因为当两个元素指向同一个不可变对象时,对其中一个赋值不会影响另外一个。
我们可以用一个包含可变对象的列表来确切地展示“浅拷贝”与“深拷贝”的区别:
>>> import copy
>>> a = [[1, 2],[5, 6], [8, 9]]
>>> b = copy.copy(a) # 浅拷贝得到b
>>> c = copy.deepcopy(a) # 深拷贝得到c
>>> print(id(a), id(b)) # a 和 b 不同
139832578518984 139832578335520
>>> for x, y in zip(a, b): # a 和 b 的子对象相同
... print(id(x), id(y))
...
139832578622816 139832578622816
139832578622672 139832578622672
139832578623104 139832578623104
>>> print(id(a), id(c)) # a 和 c 不同
139832578518984 139832578622456
>>> for x, y in zip(a, c): # a 和 c 的子对象也不同
... print(id(x), id(y))
...
139832578622816 139832578621520
139832578622672 139832578518912
139832578623104 139832578623392
从这个例子中可以清晰地看出浅拷贝与深拷贝地区别。
总结:
1、赋值:简单地拷贝对象的引用,两个对象的id相同。
2、浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。
3、深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。
浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。
Python FAQ2:赋值、浅拷贝、深拷贝的区别?的更多相关文章
- python中赋值-浅拷贝-深拷贝之间的关系
赋值: 变量的引用,没有拷贝空间 对象之间赋值本质上 是对象之间的引用传递而已.也就是多个对象指向同一个数据空间. 拷贝的对象分两种类型: . 拷贝可变类型 浅拷贝: 只拷贝第一层数据,不关心里面的第 ...
- python中赋值,深拷贝,浅拷贝区别
这三种 的区别就是 复制的变量 是否是原变量的引用. 赋值:只是原变量的引用. 浅拷贝和深拷贝的区别 需要通过 子元素 区分 浅拷贝:子元素的 引用相同 深拷贝:所以引用都不相同,完全复制一份 这三种 ...
- python开发_copy(浅拷贝|深拷贝)_博主推荐
在python中,有着深拷贝和浅拷贝,即copy模块 下面我们就来聊一下: 运行效果: ================================================== 代码部分: ...
- python的赋值,深拷贝和浅拷贝的区别
原文地址https://www.cnblogs.com/xueli/p/4952063.html 赋值:a = [1,2,3,["a","b"]] b=a,那 ...
- 深入理解Python中赋值、深拷贝(deepcopy)、浅拷贝(copy)
赋值 python跟java中的变量本质是不一样的,Python的变量实质上是一个指针(int型或str型),而java的变量是一个可操作的存储空间. a = 123b = a print(id(a) ...
- python 中的 赋值 浅拷贝 深拷贝
1.对象的赋值 都是进行对象引用(内存地址)传递,即 b is a ,a 变 b也变 2.浅拷贝 会创建一个新的对象,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址) 当我们使用下面的操作 ...
- 搞不懂JS中赋值·浅拷贝·深拷贝的请看这里
前言 百科定义:拷贝就是拷贝指向对象的指针,意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这 ...
- [Python] 等号赋值, copy, deepcopy的区别
参考链接: 1. 介绍python中的可变类型与不可变类型:https://blog.csdn.net/answer3lin/article/details/86430074 (也可以参考转载博客 P ...
- Python练习四-浅拷贝&深拷贝
一.数字.字符串不论是浅拷贝.深拷贝都是指向一个地址. a = 1 b = "abc" print (id(a)) print (id(b)) a1 = a b1 = b prin ...
- Python中的浅拷贝 深拷贝
浅拷贝只拷贝父对象,子对象的地址空间不改变,包括下面三种: 1. copy 从下面的例子可以看出对象c从a拷贝,当对象a增加一个列表元素之后,c对象没有改变, 而当对象a中的子列表改变时,对象c的子列 ...
随机推荐
- Java&Xml教程(八)使用JDOM将Java对象转换为XML
在前面的教程中我们学习了如何使用JDOM解析和修改XML文件内容,本节介绍如何将Java对象转换为XML数据并生成文件. JDOM的Document类提供了便捷的方法创建元素和属性,XMLOutput ...
- Selenium学习第二天,了解Selenium工作模式与学习Selenium需要具备的知识与工具。
Selenium学习网站: 1.http://www.ltesting.net/ceshi/open/kygncsgj/selenium/2014/0408/207237.html——好像是对API的 ...
- (转)淘淘商城系列——使用JsonView来格式化json字符串
http://blog.csdn.net/yerenyuan_pku/article/details/72846025 有时从服务端返回的json字符串往往晦涩难懂,就像下面这样,一行显示出来,让人非 ...
- centos7安装个人博客wordpress
第一步: 安装apache web 第二步: 安装MariaDB数据库 第三步: 安装PHP 第四步: 安装phpMyAdmin 第五部: 创建数据库: 第六部: 下载wordpress 第七部:复制 ...
- 网络编程-socketserver
网络编程使用socketserver,通常包括以下几步:一.定义类,并继承socketserver.BaseRequestHandler 二.重写handle方法 三.实例化TCPServer,并传递 ...
- css--小白入门篇3
一.上篇知识复习 css属性,面试的时候会有笔试,笔试没有智能感应的: ● 加粗,倾斜,下划线: 1 font-weight:bold; 2 font-style:italic; 3 text-dec ...
- TestNG设置测试用例执行优先级
@Test(priority = x)设置测试用例执行优先级.x默认为0,0的优先级最高,0>1>2>3... import org.testng.annotations.Test; ...
- AWK简单使用方法
1. 命令格式 gawk [OPTIONS] 'program' FILES.... program:'PATTERN{ACTION}' 一条awk命令中,PATTERN和ACTION,至少存在一个才 ...
- linux命令 info
info命令是Linux下info格式的帮助指令. 就内容来说,info页面比man page编写得要更好.更容易理解,也更友好,但man page使用起来确实要更容易得多.一个man page只有一 ...
- PHP代码静态分析工具PHPStan
最近发现自己写的PHP代码运行结果总跟自己预想的不一样,排查时发现大多是语法错误,在运行之前错误已经种下.可能是自己粗心大意,或者说php -l检测太简单,不过的确是有一些语法错误埋藏得太深(毕竟PH ...