copy深浅拷贝
我们在很多方法里都看到copy()方法,这是对变量的复制,赋值,下面来看一下实例:
复制方法调用的是copy模块中的方法:
import copy
copy.copy() #前拷贝
copy.deepcopy() #深拷贝
我们可以让一个变量等于另一个变量可以采用赋值的方式,比如a = b等,让变量a = b变量,还可以通过copy()来实现。下面来看看在各种情况下的关联情况:
一、字符串和数字的情况
>>> import copy
>>> a = 3
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> b
3
>>> c
3
>>> d
3
>>> print(id(a),id(b),id(c),id(d))
10914432 10914432 10914432 10914432
从上面可以看出,我们通过导入模块copy,这个模块专门用于复制,可以看到在数字中,采用赋值、copy()、deepcopy()三种方式,我们发现采用三种方式的方式,都是把地址关联过去,具有相同的地址,说明是采用如下方式进行管理的。实例如下:
从上图可以看出,在数字和字符串中,三种任意方式都是关联到字符串或数字所在的内存,是把内容关联过去,因此无论采用那种方式都是一样的
。下面来看一看在列表,元组、字符串、字典中的情况。
二、列表,元组,字典一层复制情况
列表、字典的情况
1、在列表中的情况
import copy
l = ["alex",11,"sb","tom"]
d = {"k1":"v1","k2":22,"k3":"alex"}
t = (11,'ALEX',"sb")
l1 = l
l2 = copy.copy(l)
l3 = copy.deepcopy(l)
print(id(l),id(l1),id(l2),id(l3))
#下面来修改一下列表中的元素,看看关联情况编程什么样了,如下:
l.append("Aoi")
print(l,l1,l2,l3)
print(id(l),id(l1),id(l2),id(l3))
2、在字典中的情况
d1 = d
d2 = copy.copy(d)
d3 = copy.deepcopy(d)
print(id(d),id(d1),id(d2),id(d3))
d.__setitem__("tom","Hello")
print(d,"\n",d1,"\n",d2,"\n",d3)
print(id(d),id(d1),id(d2),id(d3))
运行结果如下:
列表中的运算结果:
140006457636360 140006457636360 140006457672456 140006457637320
['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom'] ['alex', 11, 'sb', 'tom']
140006457636360 140006457636360 140006457672456 140006457637320
140006482186568 140006482186568 140006457674440 140006457636680
字典中的运算结果:
{'k2': 22, 'k3': 'alex', 'tom': 'Hello', 'k1': 'v1'}
{'k2': 22, 'k3': 'alex', 'tom': 'Hello', 'k1': 'v1'}
{'k2': 22, 'k1': 'v1', 'k3': 'alex'}
{'k2': 22, 'k1': 'v1', 'k3': 'alex'}
140006482186568 140006482186568 140006457674440 140006457636680
可以看出,在列表中我们通过等号赋值(=)、copy(list)、deepcopy(list)方法打印变量的ip地址,可以看出,等号赋值(=)与原来变量的地址是一样的,因此等号的赋值方式是这样的:
等号赋值无论在关联字典还是列表的过程中,都是指向同一个Python开辟的内存地址,a和b的内存地址永远是一致的,只要a发生了变化,相应的b就发生变化。
而在字典中copy()和deepcopy()确是下面的形式:
为什么我猜测copy()是上面的形式呢,我们来看一段代码:
import copy
l = ["alex",11,"sb","tom"]
d = {"k1":"v1","k2":22,"k3":"alex"} (1)
t = (11,'ALEX',"sb")
l1 = l
l2 = copy.copy(l)
l3 = copy.deepcopy(l)
print(id(l),id(l1),id(l2),id(l3))
#下面来修改一下列表中的元素,看看关联情况编程什么样了,如下:
l.append("Aoi")
print(l,l1,l2,l3)
print(id(l),id(l1),id(l2),id(l3))
d1 = d
d2 = copy.copy(d) (2)
d3 = copy.deepcopy(d)
print(id(d),id(d1),id(d2),id(d3)) (3)
d.__setitem__("tom","Hello")
print(d,"\n",d1,"\n",d2,"\n",d3)
print(id(d),id(d1),id(d2),id(d3)) (4)
del d["k1"] (5)
print(d,"\n",d1,"\n",d2,"\n",d3)
print(id(d),id(d1),id(d2),id(d3)) (6)
代码运行如下:
140353118074376 140353118074376 140353118110472 140353118074760
['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom', 'Aoi'] ['alex', 11, 'sb', 'tom'] ['alex', 11, 'sb', 'tom']
140353118074376 140353118074376 140353118110472 140353118074760
140353142624584 140353142624584 140353118112456 140353118075272
{'k1': 'v1', 'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
{'k1': 'v1', 'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
{'k1': 'v1', 'k2': 22, 'k3': 'alex'}
{'k1': 'v1', 'k2': 22, 'k3': 'alex'}
140353142624584 140353142624584 140353118112456 140353118075272
{'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
{'tom': 'Hello', 'k2': 22, 'k3': 'alex'}
{'k1': 'v1', 'k2': 22, 'k3': 'alex'}
{'k1': 'v1', 'k2': 22, 'k3': 'alex'}
140353142624584 140353142624584 140353118112456 140353118075272
在上面(1)处我们定义了一个字典,在(2)处我们使用copy.copy()产生一个新的变量d2,然后我们打印变量d、d2的id(d)、id(d2),我们可以看出,两者的id()是不一样的,因此可以说明在系统中是存在了两个位置存放d和d2的,而不是一个位置,仅凭这一点还不足以说明,下面来看(5)处,我们删除了字典d中的键-值对"k1",此时如果两者存在关联的话,那么d2中键-值对"k1":"v1"必然也会被删除,事实上并没有,而且我们修改元素的时候,如果它们之间存在指向关系的话,那么copy()也会让d2中的添加一个键-值对"tom":"Hell0"。事实上并没有,所以我断定,无论怎样使用copy()方法都是在内存中新开辟了一个地址,如果只有一层的话,这两个地址之间也是没有关联的。
如果字典只有一层,那么使用deepcopy()方法也是一样的,图例如下:
三、列表,元组,字典多层情况的赋值情况
上面我们研究了copy()、deepcopy()单层的情况,下面来看看多层的情况,首先定义一个字典n1={"k1":123,"k2":"wupie","k3":[123,"alex"]}
,
在python中,copy()、deepcopy()的设置挺复杂的,相同元素的id是一样的,但是在删除的时候又不会影响由copy()、deepcopy()产生的变量,
但是在使用copy()的时候,第二层的元素还是与原来的元素关联在一起,下面来看一个例子:
import copy
n1 = {"k1":123,"k2":"wupie","k3":[456,"alex"]}
#打印k1的ip地址
n2 = copy.copy(n1)
n3 = copy.deepcopy(n1)
print(n1,"\n" ,n2,"\n",n3)
print(id(n1),id(n2),id(n3))
print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")
#打印k2的地址
print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"]),"\n")
#打印"k3"的ip地址
print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"]),"\n")
#修改“k1"的值
n1["k1"] = 888
#打印修改后的信息
print(n1,"\n" ,n2,"\n",n3)
print(id(n1),id(n2),id(n3))
print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")
#打印修改后的k2的地址
print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"]),"\n")
#打印"k3"的ip地址
print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"]),"\n")
#修改"k3"中的值
n1["k3"][0] = 666
print(n1,"\n" ,n2,"\n",n3)
print(id(n1),id(n2),id(n3))
print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")
#打印修改后的k2的地址
print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"]),"\n")
#打印"k3"的ip地址
print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"]),"\n")
#删除"k3"的键值对
del n1["k3"]
print(n1,"\n" ,n2,"\n",n3)
print(id(n1),id(n2),id(n3))print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")
#打印修改后的k2的地址
print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"]),"\n")
try:#打印"k3"的ip地址
print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"]),"\n")
except KeyError:
print(id(n2["k3"]),id(n3["k3"]))id(n2),id(n3))print(id(n1["k1"]),id(n2["k1"]),id(n3["k1"]),"\n")#打印修改后的k2的地址print(id(n1["k2"]),id(n2["k2"]),id(n3["k2"]),"\n")try:#打印"k3"的ip地址 print(id(n1["k3"]),id(n2["k3"]),id(n3["k3"]),"\n")except KeyError: print(id(n2["k3"]),id(n3["k3"]))
运行结果如下:
10918272 10918272
139928163731640 139928163731640 139928163731640
139928139736520 139928139736520 139928139737608
{'k3': [666, 'alex'], 'k1': 888, 'k2': 'wupie'}
{'k3': [666, 'alex'], 'k1': 123, 'k2': 'wupie'}
{'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
139928164286856 139928139772744 139928139736968
139928164089648 10918272 10918272
139928163731640 139928163731640 139928163731640
139928139736520 139928139736520 139928139737608
{'k1': 888, 'k2': 'wupie'}
{'k3': [666, 'alex'], 'k1': 123, 'k2': 'wupie'}
{'k3': [456, 'alex'], 'k1': 123, 'k2': 'wupie'}
139928164286856 139928139772744 139928139736968
139928164089648 10918272 10918272
139928163731640 139928163731640 139928163731640
139928139736520 139928139737608
在上面例子中,我们首先定义了一个变量n1,里面嵌套了一层字典,然后使用copy(),deepcopy()生成了新的变量n2,n3并且打印了n1,n2,n3的ip地址,由ip地址可以看出,n1,n2,n3是在内存中有不同的存储位置的,接着我们打印了键-值对“k1”的存储id,结果发现,三者的“k1”存储的id位置是一样的,说明还是用的原来位置的id,这样节省了内存,接着我们看“k3”的ip地址,可以看出,使用copy()得到的ip地址与n1的“k3”的id是一样的,说明是用的一个id,我们修改字典n1中的元素"k3"之后,n2也跟着变化,说明字典n1中的“k3”和字典n2中的“k3”存在某种管理,但是当我们删除字典n1中的“k3”之后,字典n2中的"k3"不受影响,还存在,说明使用copy()生成的变量,第二层关联之间存在着某种关联,但是又不完全依存,第一层之间共用一个地址,节省了内存,但是在原来的字典发生变化的时候又不影响之前的变量,只是对新的变量开辟了一个空间,用来存放位置。
有一个监控模板,包含内存,硬盘,有一批机器,现在是按dic模式运行的,现在要修改其中一部分的及其的硬盘,其他部分不改变。
import copy
dic = {
"cpu":[80,],
"men":[80,],
"disk":[80]
}
print("before:",dic)
new_dic = copy.deepcopy(dic)
new_dic["cpu"][0] = 50
print(dic,"\n",new_dic)
在上面,我们使用copy模块的deepcopy来进行处理,我们知道,有很多信息,在嵌套中,只有deepcopy()才会生成第二层的信息。
copy深浅拷贝的更多相关文章
- 包,logging日志模块,copy深浅拷贝
一 包 package 包就是一个包含了 __init__.py文件的文件夹 包是模块的一种表现形式,包即模块 首次导入包: 先创建一个执行文件的名称空间 1.创建包下面的__init__.py文件的 ...
- Python:深浅拷贝
导入模块: >>> import copy 深浅拷贝: >>> X = copy.copy(Y) #浅拷贝:只拷贝顶级的对象,或者说:父级对象 >>&g ...
- @proprety数组字典字符串用copy和strong区别(深浅拷贝)
//// @proprety数组字典字符串用copy和strong区别(深浅拷贝).h// IOS笔记//// /* _proprety________copy_strong_________h ...
- 关于:1.指针与对象;2.深浅拷贝(复制);3.可变与不可变对象;4.copy与mutableCopy的一些理解
最近对深浅拷贝(复制)做了一些研究,在此将自己的理解写下来,希望对大家有所帮助.本人尚处在摸索阶段,希望各位予以指正. 本文包括如下方向的探索: 1.指针与对象: 2.深/浅拷贝(复制): 3.可变/ ...
- copy之深浅拷贝
深浅拷贝深拷贝 全部复制浅拷贝 只复制第一层 __author__ = 'Perfect' # -*- coding: utf-8 -*- import copy # copy.copy() #浅拷贝 ...
- 深浅拷贝的应用-copy、mutableCopy
ViewController.h #import <UIKit/UIKit.h> @interface ViewController : UIViewController //如果想让li ...
- 深浅拷贝(copy)
目录 copy 模块 1.拷贝(赋值) 1). x为不可变数据类型 2). x为可变数据类型 3). 可变数据类型(比如列表)内,既有不可变元素,又有容器类型可变元素(比如列表) 2.浅拷贝 3.深拷 ...
- Python 从零学起(纯基础) 笔记 之 深浅拷贝
深浅拷贝 1. import copy#浅拷贝copy.copy()#深拷贝copy.deepcopy()#赋值 = 2. 对于数字和字符串而言,赋值.浅拷贝和深拷贝无意义,因为其永远指向同一个 ...
- python——赋值与深浅拷贝
初学编程的小伙伴都会对于深浅拷贝的用法有些疑问,今天我们就结合python变量存储的特性从内存的角度来谈一谈赋值和深浅拷贝~~~ 预备知识一——python的变量及其存储 在详细的了解python中赋 ...
随机推荐
- [linux]linuxI/O测试的方法之dd
参考http://www.thomas-krenn.com/en/wiki/Linux_I/O_Performance_Tests_using_dd Measuring Write Performan ...
- Qt ------ QElapsedTimer 计算消耗多少时间
The QElapsedTimer class provides a fast way to calculate elapsed times. The QElapsedTimer class is u ...
- C ------ static 关键字的作用
首先要理解生存周期与作用域的区别: 生存周期: 变量从定义到销毁的时间范围.存放在全局数据区的变量的生存周期存在于整个程序运行期间,而存放在栈中的数据则随着函数等的作用域结束导致出栈而销毁,除了静态变 ...
- DevExpress 常用命令包括导出-打印-打印预览等
3.表格打印也是最常见的,打印代码如下: PrintingSystem ps = null; DevExpress.XtraPrinting.PrintableComponentLink link = ...
- [linux]codeblocks开发mysql配置
1.在安装好mysql后,可以应该安装必要的库文件 $sudo apt-get install libmysqlclient-dev 2.将codeblocks与mysql的库文件连接起来 在code ...
- Date、String、Calendar相互转化
Date是在Jdk1.0出现的专门用来处理时间的类,但是由于Date在国际化方面存在限制,在Jdk1.1推出Calendar,现在Date的很多方法都已经过时,都迁移到Calendar上. 1.Dat ...
- 线程池-Threadlocal
ThreadLoclc初衷是线程并发时,解决变量共享问题,但是由于过度设计,比如弱引用的和哈希碰撞,导致理解难度大.使用成本高,反而成为故障高发点,容易出现内存泄露,脏数据.贡献对象更新等问题.单从T ...
- webpack4 未设置mode会自动压缩
最近想用LayaBox做个小游戏,然而Laya本身不自带构建工具.然后觉得写模块化的东西还是用webpack好使,用es6的语法也比较清晰. 于是就装了webpack,只用babel-loader来编 ...
- 【leetcode 简单】第三十四题 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次.找出那个只出现了一次的元素. 说明: 你的算法应该具有线性时间复杂度. 你可以不使用额外空间来实现吗? 示例 1: 输入: [ ...
- 5、Linux操作系统介绍
1操作系统的作用·是现代计算机系统中最基本和最重要的系统软件·是配置在计算机硬件上的第一层软件,是对硬件系统的首次扩展·主要作用是管理好硬件设备,并为用户和应用程序提供一个简单的接口,以便于使用·而其 ...