这篇文章主要介绍了Python中的赋值、浅拷贝、深拷贝介绍,Python中也分为简单赋值、浅拷贝、深拷贝这几种“拷贝”方式,需要的朋友可以参考下
 
和很多语言一样,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中的赋值、浅拷贝、深拷贝介绍的更多相关文章

  1. python 中的 赋值 浅拷贝 深拷贝

    1.对象的赋值 都是进行对象引用(内存地址)传递,即 b is a ,a 变 b也变 2.浅拷贝 会创建一个新的对象,对于对象中的元素,浅拷贝就只会使用原始元素的引用(内存地址) 当我们使用下面的操作 ...

  2. Python中的赋值、深拷贝与浅拷贝(内存地址)

    Python中的赋值.深拷贝与浅拷贝(内存地址) 1.python中的可变对象与不可变对象 (1) 可变对象:dict,list def dict_test(): a = {} b = a print ...

  3. Python中的赋值和拷贝

    赋值 在python中,赋值就是建立一个对象的引用,而不是将对象存储为另一个副本.比如: >>> a=[1,2,3] >>> b=a >>> c= ...

  4. python中的“赋值与深浅拷贝”

    Python中,赋值与拷贝(深/浅拷贝)之间是有差异的,这主要源于数据在内存中的存放问题,本文将对此加以探讨. 1 赋值(添加名字) 赋值不会改变内存中数据存放状态,比如在内存中存在一个名为data的 ...

  5. python中的赋值操作和复制操作

    之前一直写C#,变量之间赋值相当于拷贝,修改拷贝变量不会改变原来的值.但是在python中发现赋值操作本质是和C++中的引用类似,即指向同一块内存空间.下面通过一个例子说明: p=[0,1,2,3,4 ...

  6. python中的赋值操作

    参考:https://www.cnblogs.com/andywenzhi/p/7453374.html?tdsourcetag=s_pcqq_aiomsg(写的蛮好) python中的赋值操作“=” ...

  7. python中的赋值和深浅拷贝

    python中,A object  = B object  是一种赋值操作,赋的值不是一个对象在内存中的空间,而只是这个对象在内存中的位置 . 此时当B对象里面的内容发生更改的时候,A对象也自然而然的 ...

  8. (数据科学学习手札32)Python中re模块的详细介绍

    一.简介 关于正则表达式,我在前一篇(数据科学学习手札31)中已经做了详细介绍,本篇将对Python中自带模块re的常用功能进行总结: re作为Python中专为正则表达式相关功能做出支持的模块,提供 ...

  9. Python 中的赋值、拷贝、引用

    在 python 中赋值语句总是建立对象的引用值,而不是复制对象.因此,python 变量更像是指针,而不是数据存储区域. 如图所示,当改变一个变量的值,另一个的值也会跟着改变.也就是浅拷贝. 若要实 ...

随机推荐

  1. 什么是业务运维,企业如何实现互联网+业务与IT的融合

    业务运维并不是一个新概念,针对传统信息架构提出的业务服务管理就是把以业务为核心的IT系统与IT基础设施性能进行整合运维的解决方案.然而随着互联网+转型的不断推进,基础设施的智能化和广泛云化成为IT发展 ...

  2. PHP用户名用星号处理

    PHP用户名用*号处理: 用户名:英文.中文.中英文混合的.中英文字符混合的 处理为:首字母和末尾保留,中间用*号代替(一个字符直接显示,两个字符:张*,三个以上字符:宋*丹) 首先判断字符中是否包含 ...

  3. HDU 4831 Scenic Popularity

    Scenic Popularity Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  4. Unity协程截图,WWWForm、WWW配合上传

    先说一下原理.. 截图有两种方法,第一种: Application.CaptureScreenshot(url); 这个API可以截全屏并保存到指定路径 这里我们不采用此方法 下面的代码采用第二种方法 ...

  5. GTD

    这两天坚持GTD,四分象限法管理时间,感觉学习专注度明显提升,一直没完成的马士兵JAVA基础整到第八章了,继续保持,1.13号前争取11章全整完. 3个点支撑起你的职业发展:技术,管理(管理自己.管理 ...

  6. chrome浏览器开发者工具之同步修改至本地

    相信好多小伙伴喜爱webpack的热加载技术,省时而又不繁琐,讨厌F5或者Ctrl+F5. 嘿嘿,现在介绍大家一个在浏览器中修改直接同步到本地代码修改的方法--- (程序员都是从0开始数数的!) 第0 ...

  7. 改变jboss部署目录(虚拟目录)

    笔记: 在开发过程中,有时候我们希望将程序放在我们的源代码目录中,比如d:\code下,而不是放在jboss的deploy下,怎么办? 我们知道,jboss中集成了tomcat,因此跟tomcat一样 ...

  8. 乌邦图ubuntu配置iptables的NAT上网

    cat /etc/network/iptables.up.rules # Generated by iptables-save v1. :: *nat :PREROUTING ACCEPT [:] : ...

  9. C# log4net输出发生错误的行号

    别人调用我写的接口,总是报错,但我这测试是没问题的,就想着用log4net来跟踪一下. 跟踪后,发现接口确实有出错的日志,但是没有具体出错的地方. 通过输出日志的方式,跟踪不是很方便,就想着log4n ...

  10. #include <cstdio>

    #include <cstdio> using namespace std; int main() { int gx; gx=6; printf("%d\n",gx); ...