深浅copy详解
一. 前言
在python中,对象的赋值和深浅copy,是有差异的.最终得的值也不同,下面我们就通过几个例子,来看下它们之间的区别.
二. 赋值
list2 = ["jack",22,["65kg","170cm"]]
#对象赋值操作
list3 = list2
print("修改前list2的内存地址:",id(list2))
print("修改前list3的内存地址:",id(list3))
print("修改前list2中元素的内存地址:",[id(x) for x in list2])
print("修改前list3中元素的内存地址:",[id(x) for x in list3])
list2[0] = 1
list2[2][0]="60kg" print("修改后list2的内存地址:",id(list2))
print("修改后list3的内存地址:",id(list3))
print("修改后list2中元素的内存地址:",[id(x) for x in list2])
print("修改后list3中元素的内存地址:",[id(x) for x in list3])
print("list2:%s"%list2)
print("list3:%s"%list3)
修改前list2的内存地址: 43781448
修改前list3的内存地址: 43781448
修改前list2中元素的内存地址: [43775120, 1389588608, 43782216]
修改前list3中元素的内存地址: [43775120, 1389588608, 43782216]
修改后list2的内存地址: 43781448
修改后list3的内存地址: 43781448
修改后list2中元素的内存地址: [1389587936, 1389588608, 43782216]
修改后list3中元素的内存地址: [1389587936, 1389588608, 43782216]
list2:[1, 22, ['60kg', '170cm']]
list3:[1, 22, ['60kg', '170cm']]
赋值操作:其实是指向了值的内存地址.修改list2[2][0],list3中的数据也跟着变了.这时打印输出list2和list3中[2][0],发现它们指向的都是同一个内存地址.且无论是修改list2还是修改list3
效果都是一样的.
三. 浅copy
#浅copy,只copy对象和子对象,不会对子对象中的数据进行copy list2 = ["jack",22,["65kg","170cm"]]
list3 = list2[:]
# list3 = list2.copy()
print("修改前list2的内存地址:",id(list2))
print("修改前list3的内存地址:",id(list3))
print("修改前list2中元素的内存地址:",[id(x) for x in list2])
print("修改前list3中元素的内存地址:",[id(x) for x in list3])
list2[0] = 1
list2[2][0]="60kg"
12 list3[2][0] = "70kj"
print("修改后list2的内存地址:",id(list2))
print("修改后list3的内存地址:",id(list3))
15 print("修改后list2中元素的内存地址:",[id(x) for x in list2])
16 print("修改后list3中元素的内存地址:",[id(x) for x in list3])
print([id(x) for x in list2])
18 print("list2:%s"%list2)
19 print("list3:%s"%list3) print(id(list2[2][0]))
print(id(list3[2][0]))
------------------------------------------------------------------------------------
修改前list2的内存地址: 37485896
修改前list3的内存地址: 37486472
修改前list2中元素的内存地址: [37487704, 1371107456, 37490760]
修改前list3中元素的内存地址: [37487704, 1371107456, 37490760]
修改后list2的内存地址: 37485896
修改后list3的内存地址: 37486472
30 修改后list2中元素的内存地址: [1371106784, 1371107456, 37490760]
31 修改后list3中元素的内存地址: [37487704, 1371107456, 37490760]
[1371106784, 1371107456, 37490760]
33 list2:[1, 22, ['70kj', '170cm']]
34 list3:['jack', 22, ['70kj', '170cm']]
37509976
37509976
总结:浅copy,在copy一个对象时,会创建一个新的对象(第24,25即可看出,list2和list3是2个不同的对象),但是子对象的中的(对象)数据依然是引用被copy对象的指向的内存地址的值.
四. 深copy
# 深copy,完整的copy一个对象,生成一个全新的对象.
import copy
list2 = ["jack",22,["65kg","170cm"]]
list3=copy.deepcopy(list2)
print("修改前list2的内存地址:",id(list2))
print("修改前list3的内存地址:",id(list3))
7 print("修改前list2中元素的内存地址:",[id(x) for x in list2])
8 print("修改前list3中元素的内存地址:",[id(x) for x in list3])
list2[0] = 1
list2[2][0]="60kg"
list3[2][0] = "70kj"
print("修改后list2的内存地址:",id(list2))
print("修改后list3的内存地址:",id(list3))
14 print("修改后list2中元素的内存地址:",[id(x) for x in list2])
15 print("修改后list3中元素的内存地址:",[id(x) for x in list3])
print([id(x) for x in list2])
17 print("list2:%s"%list2)
18 print("list3:%s"%list3) print(id(list2[2][0]))
print(id(list3[2][0]))
---------------------------------------------------------------------------------------
修改前list2的内存地址: 43777352
修改前list3的内存地址: 43777928
25 修改前list2中元素的内存地址: [43779160, 1371107456, 43782216]
26 修改前list3中元素的内存地址: [43779160, 1371107456, 43777864]
修改后list2的内存地址: 43777352
修改后list3的内存地址: 43777928
29 修改后list2中元素的内存地址: [1371106784, 1371107456, 43782216]
30 修改后list3中元素的内存地址: [43779160, 1371107456, 43777864]
[1371106784, 1371107456, 43782216]
32 list2:[1, 22, ['60kg', '170cm']]
33 list3:['jack', 22, ['70kj', '170cm']]
43801376
43801432
深copy:会创建一个全新的对象.在未对数据进行修改的情况下,默认2个对象的元素(不可变类型)指向的是一个内存地址(但是不包括可变的类型的子对象,可变类型会重新创建一个开辟一个新的内存空间,用来存放自己的数据).下面代码中,前4个元素都是不可变类型,所以在2个列表中,指向的都是同一个内存地址.后面可变的数据类型的元素,list3都重新创建了新的内存空间来存放数据. 不可变类型修改时,会重新开辟新的内存空间,不在指向原来的内存空间.
import copy
list2 = ["jack",22,("a","b"),True,["65kg","170cm"],{"k1":"v1"},{1,2,3,4}]
list3=copy.deepcopy(list2)
print("list2中元素的内存地址:",[id(x) for x in list2])
print("list3中元素的内存地址:",[id(x) for x in list3])
print("list2:%s"%list2)
print("list3:%s"%list3) print(id(list2[4][0])) #查看第5个元素中的子元素的内存地址
print(id(list3[4][0])) --------------------------------------------------------------------------------------------
list2中元素的内存地址: [37418128, 495874176, 37427208, 495382752, 37424840, 31333400, 37414952]
list3中元素的内存地址: [37418128, 495874176, 37427208, 495382752, 37421192, 32129888, 37416072]
list2:['jack', 22, ('a', 'b'), True, ['65kg', '170cm'], {'k1': 'v1'}, {1, 2, 3, 4}]
list3:['jack', 22, ('a', 'b'), True, ['65kg', '170cm'], {'k1': 'v1'}, {1, 2, 3, 4}]
37418408
37418408
特殊情况:如果元祖中包含的是一个可变的数据类型(字典,集合,列表),则不能进行深copy.(而是新开辟内存空间来存放)
import copy
list2 = [([10,12,13])]
list3=copy.deepcopy(list2)
print("list2中元素的内存地址:",[id(x) for x in list2])
print("list3中元素的内存地址:",[id(x) for x in list3])
print("list2:%s"%list2)
print("list3:%s"%list3)
--------------------------------------------------------------------------------------------
list2中元素的内存地址: [43515592]
list3中元素的内存地址: [43511944]
list2:[[10, 12, 13]]
list3:[[10, 12, 13]]
五. 深浅copy总结
- Python中对象的赋值都是进行对象引用(内存地址)传递
- 使用copy.copy(),可以进行对象的浅拷贝,它复制了对象,但对于对象中的元素,依然使用原始的引用.
- 如果需要复制一个容器对象,以及它里面的所有元素(包含元素的子元素),可以使用copy.deepcopy()进行深拷贝
- 对于非容器类型(如数字、字符串、和其他'原子'类型的对象)没有被拷贝一说,都是重新开辟内存空间来存放数据
- 如果元祖变量只包含原子类型对象,则不能深拷贝
深浅copy详解的更多相关文章
- Python的深浅copy详解
Python的深浅copy详解 目录 Python的深浅copy详解 一.浅copy的原理 1.1 浅copy的定义 1.2 浅copy的方法 二.深copy的原理 2.1 深copy的定义 2.2 ...
- python 的内存回收,及深浅Copy详解
一.python中的变量及引用 1.1 python中的不可变类型: 数字(num).字符串(str).元组(tuple).布尔值(bool<True,False>) 接下来我们讲完后你就 ...
- 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS
深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...
- IOS开发之深拷贝与浅拷贝(mutableCopy与Copy)详解
copy与retain的区别: copy是创建一个新对象,retain是创建一个指针,引用对象计数加1.Copy属性表示两个对象内容相同,新的对象retain为1 ,与旧有对象的引用计数无关,旧有对象 ...
- Python列表深浅复制详解
转自:https://www.cnblogs.com/blaomao/p/7239203.html 在文章<Python 数据类型>里边介绍了列表的用法,其中列表有个 copy() 方法, ...
- Python 列表深浅复制详解
在文章<Python 数据类型>里边介绍了列表的用法,其中列表有个 copy() 方法,意思是复制一个相同的列表.例如 names = ["小明", "小红& ...
- ARC声明属性关键字详解(strong,weak,unsafe_unretained,copy)
ARC声明属性关键字详解(strong,weak,unsafe_unretained,copy) 在iOS开发过程中,属性的定义往往与retain, assign, copy有关,我想大家都很熟悉了, ...
- 转载爱哥自定义View系列--Paint详解
上图是paint中的各种set方法 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfermode.ColorFilt ...
- Python数据类型及其方法详解
Python数据类型及其方法详解 我们在学习编程语言的时候,都会遇到数据类型,这种看着很基础也不显眼的东西,却是很重要,本文介绍了python的数据类型,并就每种数据类型的方法作出了详细的描述,可供知 ...
随机推荐
- linux学习笔记整理(三)
第四章 文件的基本管理和XFS文件系统备份恢复本节所讲内容:4.1 Linux系统目录结构和相对/绝对路径.4.2 创建/复制/删除文件,rm -rf / 意外事故4.3 查看文件内容的命令4.4 实 ...
- Zookeeper的一致性
转载:http://flyfoxs.iteye.com/blog/2121560 下面内容主要摘抄于<<Hadoop实战>>,红色高亮部分是本人添加的白话注释. Zookeep ...
- Tesseract-OCR识别
参考 https://studygolang.com/topics/4527/comment/13217 安装版Windows下链接: https://digi.bib.uni-mannheim.de ...
- 【转】java将excel文件转换成txt格式文件
在实际应用中,我们难免会遇到解析excel文件入库事情,有时候为了方便,需要将excel文件转成txt格式文件.下面代码里面提供对xls.xlsx两种格式的excel文件解析,并写入到一个新的txt文 ...
- python装饰器(备忘)
# 装饰器decorator def deco1(fun): def PRINT(*args,**kwargs): print('------deco1------') fun(*args,**kwa ...
- spring 、spring boot 常用注解
@Profile 1.用户配置文件注解. 2.使用范围: @Configration 和 @Component 注解的类及其方法, 其中包括继承了 @Component 的注解: @Service. ...
- Apollo 3.0 硬件与系统安装指南
https://github.com/ApolloAuto/apollo/blob/master/docs/quickstart/apollo_3_0_hardware_system_installa ...
- keystone系列三:网关协议
一 静态页面和动态页面 在了解了http协议后,我们知晓,一个web server的本质就是 浏览器发送一个HTTP请求: 服务器收到请求,生成一个HTML文档: 服务器把HTML文档作为HTTP响应 ...
- LOJ6036 编码 2-SAT、Trie
传送门 每个串只有一个?,?还只能填0或者1,不难想到2-SAT求解. 一个很暴力的想法是枚举?填0或者1,然后对所有可能的前缀连边.这样边数是\(O(n^2)\)的,需要优化. 看到前缀不难想到Tr ...
- C# 下载文件
最近一段时间,真的是太忙太忙了!经历了自我毕业以来最忙碌的一个项目! 说起这个项目,我有万千感慨 且不说技术能力,也无需谈论项目需求.单就项目压力,日常加班,周六日补班而言,我相信很多人是扛不住的! ...