【转】Python中的赋值、浅拷贝、深拷贝介绍
在学习过程中,一开始对浅拷贝理解很模糊。不过经过一系列的实验后,我发现对这三者的概念有了进一步的了解。
一、赋值
赋值算是这三种操作中最常见的了,我们通过一些例子来分析下赋值操作:
str例
>>> a = 'hello'
>>> b = 'hello'
>>> c = a
>>> [id(x) for x in a,b,c]
[4404120000, 4404120000, 4404120000]
由以上指令中,我们可以发现a, b, c三者的地址是一样的。所以以上赋值的操作就相当于c = a = b = 'hello'。
赋值是系统先给一个变量或者对象(这里是'hello')分配了内存,然后再将地址赋给a, b, c。所以它们的地址是相同的。
list例
>>> a = ['hello']
>>> b = ['hello']
>>> c = a
>>> [id(x) for x in a,b,c]
[4403975952, 4404095096, 4403975952]
但是这种情况却不一样了,a和b的地址不同。为何?
因为str是不可变的,所以同样是'hello'只有一个地址,但是list是可变的,所以必须分配两个地址。
这时,我们希望探究以上两种情况如果 修改值 会如何?
str例
>>> a = 'world'
>>> [id(x) for x in a,b,c]
[4404120432, 4404120000, 4404120000]
>>> print a, b, c
world hello hello
这时a的地址和值变了,但是b, c地址和值都未变。因为str的不可变性,a要重新赋值则需重新开辟内存空间,所以a的值改变,a指向的地址改变。b, c由于'hello'的不变性,不会发生改变。
list例
>>> a[0] = 'world'
>>> [id(x) for x in a,b,c]
[4403975952, 4404095096, 4403975952]
>>> print a, b, c
['world'] ['hello'] ['world']
这时a, c的值和地址均改变,但二者仍相同,b不改变。由于list的可变性,所以修改list的值不需要另外开辟空间,只需修改原地址的值。所以a, c均改变。
在了解了以上的不同点之后,我们就能很好地分析浅拷贝和深拷贝了。
我们均用list作为例子。
二、浅拷贝
>>> a = ['hello', [123, 234]]
>>> b = a[:]
>>> [id(x) for x in a,b]
[4496003656, 4496066752]
>>> [id(x) for x in a]
[4496091584, 4495947536]
>>> [id(x) for x in b]
[4496091584, 4495947536]
Line3,4可以看出a, b地址不同,这符合list是可变的,应开辟不同空间。那浅拷贝就是拷贝了一个副本吗?再看Line5 - 8,我们发现a, b中元素的地址是相同的。如果说字符串'hello'地址一致还能理解,但是第二个元素是list地址仍一致。 这就说明了浅拷贝的特点,只是将容器内的元素的地址复制了一份 。
接着我们尝试修改a, b中的值:
>>> a[0] = 'world'
>>> a[1].append(345)
>>> print 'a = ', a, '\n\r', 'b = ', b
a = ['world', [123, 234, 345]]
b = ['hello', [123, 234, 345]]
a中第一个元素str改变,但是b中未改变;a中第二个元素改变,b中也改变。这就符合不可变的对象修改会开辟新的空间,可变的对象修改不会开辟新空间。也进一步证明了 浅拷贝仅仅是复制了容器中元素的地址 。
三、深拷贝
>>> from copy import deepcopy
>>> a = ['hello', [123, 234]]
>>> b = deepcopy(a)
>>> [id(x) for x in a, b]
[4496066824, 4496066680]
>>> [id(x) for x in a]
[4496091584, 4496067040]
>>> [id(x) for x in b]
[4496091584, 4496371792]
深拷贝后,可以发现a, b地址以及a, b中元素地址均不同。这才是完全 拷贝了一个副本 。
修改a的值后:
>>> a[0] = 'world'
>>> a[1].append(345)
>>> print 'a = ', a, '\n\r', 'b = ', b
a = ['world', [123, 234, 345]]
b = ['hello', [123, 234]]
从Line4,5中可以发现仅仅a修改了,b没有任何修改。 因为b是一个完全的副本,元素地址均与a不同,a修改,b不受影响 。
总结:
1. 赋值是将一个对象的地址赋值给一个变量,让变量指向该地址( 旧瓶装旧酒 )。
2. 浅拷贝是在另一块地址中创建一个新的变量或容器,但是容器内的元素的地址均是源对象的元素的地址的拷贝。也就是说新的容器中指向了旧的元素( 新瓶装旧酒 )。
3. 深拷贝是在另一块地址中创建一个新的变量或容器,同时容器内的元素的地址也是新开辟的,仅仅是值相同而已,是完全的副本。也就是说( 新瓶装新酒 )。
【转】Python中的赋值、浅拷贝、深拷贝介绍的更多相关文章
- python 中的 赋值 浅拷贝 深拷贝
1.对象的赋值 都是进行对象引用(内存地址)传递,即 b is a ,a 变 b也变 2.浅拷贝 会创建一个新的对象,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址) 当我们使用下面的操作 ...
- Python中的赋值、深拷贝与浅拷贝(内存地址)
Python中的赋值.深拷贝与浅拷贝(内存地址) 1.python中的可变对象与不可变对象 (1) 可变对象:dict,list def dict_test(): a = {} b = a print ...
- Python中的赋值和拷贝
赋值 在python中,赋值就是建立一个对象的引用,而不是将对象存储为另一个副本.比如: >>> a=[1,2,3] >>> b=a >>> c= ...
- python中的“赋值与深浅拷贝”
Python中,赋值与拷贝(深/浅拷贝)之间是有差异的,这主要源于数据在内存中的存放问题,本文将对此加以探讨. 1 赋值(添加名字) 赋值不会改变内存中数据存放状态,比如在内存中存在一个名为data的 ...
- python中的赋值操作和复制操作
之前一直写C#,变量之间赋值相当于拷贝,修改拷贝变量不会改变原来的值.但是在python中发现赋值操作本质是和C++中的引用类似,即指向同一块内存空间.下面通过一个例子说明: p=[0,1,2,3,4 ...
- python中的赋值操作
参考:https://www.cnblogs.com/andywenzhi/p/7453374.html?tdsourcetag=s_pcqq_aiomsg(写的蛮好) python中的赋值操作“=” ...
- python中的赋值和深浅拷贝
python中,A object = B object 是一种赋值操作,赋的值不是一个对象在内存中的空间,而只是这个对象在内存中的位置 . 此时当B对象里面的内容发生更改的时候,A对象也自然而然的 ...
- (数据科学学习手札32)Python中re模块的详细介绍
一.简介 关于正则表达式,我在前一篇(数据科学学习手札31)中已经做了详细介绍,本篇将对Python中自带模块re的常用功能进行总结: re作为Python中专为正则表达式相关功能做出支持的模块,提供 ...
- Python 中的赋值、拷贝、引用
在 python 中赋值语句总是建立对象的引用值,而不是复制对象.因此,python 变量更像是指针,而不是数据存储区域. 如图所示,当改变一个变量的值,另一个的值也会跟着改变.也就是浅拷贝. 若要实 ...
随机推荐
- Math
Math.sin(t) // sin(t) Math.power(x,2*i) // x的2i次方 (double)(Math.round(sum*1000000))/1000000; / ...
- Linux下JDK、Tomcat
1.JDK的安装 1. 下载JDK 先查看Linux系统是多少位(32位/64位):getconf LONG_BIT.再从JDK官网(http://www.oracle.com/technetw ...
- 转载:jQuery实现返回顶部功能
转自:http://blog.csdn.net/itmyhome1990/article/details/25340705 整理两个实现功能,一个是右下角的返回顶部,一个是右侧的返回顶部,分别如图 ...
- Android中webview和js之间的交互(转)
http://www.cnblogs.com/leizhenzi/archive/2011/06/29/2093636.html 1.android中利用webview调用网页上的js代码. Andr ...
- Light OJ 1032 - Fast Bit Calculations(数学)
题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1032 题目大意:一个十进制数变化为二进制,那么对于这个数,如果连着两个二进制位 ...
- Android开发LogCat一直不停输出的解决方法
加一个过滤器 如图,选择Saved Filter + 然后如下图: 然后再选择OK就可以啦!!!
- C++中数据对齐
大体看了看数据对齐,不知道是否正确,总结如下: struct A { char name; double dHeight; int age; }; sizeof(A) = (1+7+8+4+4) = ...
- 金蝶K/3 Cloud 界面解析过程
服务端 目前也就是iis服务器生成Json描述返回给不同的展现端最解析. 不同的展现端,可以有Silverlight.WPF.Html5.Winform 当然还有IOS和Android端做解析展现 对 ...
- Oracle 12c 的新功能:模式匹配查询
模式匹配SQL 在一系列的数据行中辨识出某种模式是一种广泛需求的功能,但在以前的SQL中是不可能的.有许多解决方法,但这些都很难写,很难理解,而且执行效率低下.在Oracle数据库中,从12c开始,你 ...
- 【Docker 在 windows 10 / windows 8 下安装】
步骤: 1. 下载: a.https://github.com/boot2docker/windows-installer/releases 下载一个 windows 客户端: 安装时建议勾选:Boo ...