详解Python直接赋值,深拷贝和浅拷贝
直接赋值: 对象的引用,也就是给对象起别名 浅拷贝: 拷贝父对象,但是不会拷贝对象的内部的子对象。 深拷贝: 拷贝父对象. 以及其内部的子对象
在之前的文章中,提到可变对象和不可变对象,接下来也是以这两者的区别进行展开
直接赋值
对于可变对象和不可变对象,将一个变量直接赋值给另外一个变量,两者 id 值一致,其实本质上是将变量量绑定到对象的过程.
a=1
b=a
id(a) == id(b)
True
c="string"
d=c
id(c) == id(d)
True
e=[1,2,3]
f=e
id(e)==id(f)
True
关于修改新变量的值,对原有变量会产生的影响,在可变对象和不可变对象 中也做了讲述,这里通过几个例子,重新温习一下
不可变对象
x=1
y=x
id(x)==id(y)
True
id(1)==id(y)
True
id(x)
1500143776
y=y+1
y
2
x
1
id(x)==id(y)
False
id(y)
1500143808
id(x)
1500143776
对于不可变对象,修改赋值后的新变量,不会对原有变量造成任何影响.为什么出现这种现象呢?因为不可变对象一旦创建之后就不允许被改变.后面对 y
进行的操作,其实是重新创建一个对象并绑定的结果:
可变对象
m=[1,2,3]
n=m
id(n)==id(m)
True
id(m)
1772066764488
id(n[0])
1772066764656
n[0]=4
n
[4, 2, 3]
m
[4, 2, 3]
id(n)==id(m)
True
id(m)
1772066764488
对于可变对象,修改赋值后的变量,会对原有的变量造成影响,会导致其 value
值的改变,但是其id
值保持不变
从上图不难看出,这个时候的 id(n[0]) 的值,和未修改前的 id值应该不一样,可以输出看一下
id(n[0])
1772066764752 # 最初没有修改前是 1772066764656
n[0]
修改前后为什么 id 值出现改变呢? 首先需要明确一点 n[0]
绑定的是一个不可变对象,在文章的最初提到,不可变对象一旦创建就不允许修改.显然对 n[0]
进行修改,不能在绑定对象的内存上进行修改,那如何实现重新赋值呢?只能创建一个新的对象 4
,然后将 n[0]
绑定到新的对象
浅拷贝和深拷贝
先看一下官方文档的定义
The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances). A shallow copy constructs a new compound object and then (to the extent possible) inserts the same objects into it that the original contains. A deep copy constructs a new compound object and then, recursively,inserts copies into it of the objects found in the original.
从文档中不难看出,上面提到深拷贝和浅拷贝两者区别在于在复合对象,那接下来也只讨论复合对象.
浅拷贝
注意到官方文档也提到对浅拷贝和深拷贝的定义,从上文中不难看出,浅拷贝构建一个复合对象,然后将原有复合对象包含的对象插入到新的复合对象中
从上图不难看出,浅拷贝后,新复合对象包含的对象(可变或者不可变)的 id 值和原有对象包含的对象的 id 值相同
看一下具体例子:
import copy
a=[1,2,[3,4]]
b=copy.copy(a)
id(b[0])==id(a[0])
True
id(b[2])==id(a[2])
True
id(b[2][0])==id(a[2][0])
True
现在让我们试着修改一下浅拷贝后的 b
的值,在修改前,可以先思考一下,如果修改 b[0]
可能会发生什么?
由于 b[0] = 1
,很显然 1 属于不可变对象,那么根据对不可变变量修改的规则,则 b[0]
会绑定到新的变量上,而 a[0]
的由于没有修改,则保持不变,真的是这样吗?让我们验证一下
b[0]=5
b
[5, 2, [3, 4]]
a
[1, 2, [3, 4]]
接下来我们要尝试修改一下 b[2]
,由于 b[2]
绑定的对象是 list
,属于可变对象,按照上面说的可变对象修改的规则,则修改后的 b[2]
的 id
值保持不变,但是其 value
值会发生改变. 同样的让我们通过例子验证一下
id(b[2])
4300618568
b[2][0]=6
id(b[2])
4300618568
b
[5, 2, [6, 4]]
a
[1, 2, [6, 4]]
由于 b[2]
和 a[2]
绑定同一个可变对象,很显然对 b[2]
的修改同样会映射到 a[2]
上
深拷贝
深拷贝构建一个复合对象,然后递归的将原有复合包含的对象的副本插入到新的复合对象中
若上图所示,深拷贝后,新的复合对象包含的对象,若对象为不可变对象,则 id 值保持不变,若对象为可变对象,则 id 值发生改变
看一个例子:
import copy
a=[1,2,[3,4]]
b=copy.deepcopy(a)
id(b[0])==id(a[0])
True
id(b[2])==id(a[0])
False
id(b[2][0])==id(a[2][0])
True
接下来让我们修改一下变量 b
,这里就不在修改不可变对象 b[0]
和 b[1]
了,因为结果很明显,对 a 不会产生任何影响,我们来修改 b[2]
,那么修改 b[2]
会对 a[2]
产生影响吗?很明显答案是不会,因为深拷贝就相当于克隆出了一个全新的个体,两者不再有任何关系
b[2][0]=5
b
[1, 2, [5, 4]]
a
[1, 2, [3, 4]]
- 斐波那契数列与IE9
- DateTime.ToString()输出"年/月/日 时:分:秒"的格式
- Flash在线拍摄用户头象
- win7 64位下如何折腾Tubro C 3.0
- TweenLite的又一应用:图片的拼图加载效果
- mysql创建数据表时如何判断是否已经存在?
- 温故知新:接口的隐式实现与显式实现
- 也谈枚举ToString()性能的改进
- silverlight:利用telerik中的zip类对字符串进行压缩、解压
- 索引,视图,存储过程和触发器文档
- 重点解读:用小程序给公众号涨粉10w的7大行业案例
- 网络域名与注册商标冲突的解决途径
- 网站代码优化我们必须要做的那些事
- 真是热闹! Slade.com等多个域名被曝交易
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 深入了解ActiveMQ!
- 完美解决 python ImportError: Failed to import any qt binding
- 爬取娱乐圈排行榜数据
- 如何解决Linux系统下pyaudio安装缺少文件问题error: portaudio.h: 没有那个文件或目录
- pytest 测试框架学习(10):pytest.param
- pytest 测试框架学习(11):pytest.raises
- Hibernate第二天:Hibernate的一级缓存、其他的API
- pytest 测试框架学习(12):pytest.deprecated_call
- Pinstaller(Python打包为exe文件
- pytest 测试框架学习(14):pytest.warns
- ImportError: /lib64/libm.so.6: version `CXXAB_1.3.8.' not found (required by /usr/local/python37/lib
- pytest 测试框架学习(15):pytest.freeze_includes
- Linux: scp文件,目录上传下载标准版
- Hibernate第三天:Hibernate的一对多配置、Hibernate的多对多的配置
- Git: 掉坑记 -- git reset 杀手