Python深浅拷贝

预备知识一——python的变量及其存储

在详细的了解python中赋值、copy和deepcopy之前,我们还是要花一点时间来了解一下python内存中变量的存储情况。
在高级语言中,变量是对内存及其地址的抽象。对于python而言,python的一切变量都是对象,变量的存储,采用了引用语义的方式,存储的只是一个变量的值所在的内存地址,而不是这个变量的只本身。

引用语义:

在python中,变量保存的是对象(值)的引用,我们称为引用语义。采用这种方式,变量所需的存储空间大小一致,因为变量只是保存了一个引用。也被称为对象语义和指针语义。

值语义:

有些语言采用的不是这种方式,它们把变量的值直接保存在变量的存储区里,这种方式被我们称为值语义,例如C语言,采用这种存储方式,每一个变量在内存中所占的空间就要根据变量实际的大小而定,无法固定下来。

值语义和引用语义的区别:

值语义: 死的、 傻的、 简单的、 具体的、 可复制的
引用语义: 活的、 聪明的、 复杂的、 抽象的、 不可复制的

Paste_Image.png

预备知识二——各基本数据类型的地址存储及改变情况

由于python中的变量都是采用的引用语义,数据结构可以包含基础数据类型,导致了在python中数据的存储是下图这种情况,每个变量中都存储了这个变量的地址,而不是值本身;对于复杂的数据结构来说,里面的存储的也只只是每个元素的地址而已。:

Paste_Image.png

1.数据类型重新初始化对python语义引用的影响

变量的每一次初始化,都开辟了一个新的空间,将新内容的地址赋值给变量。对于下图来说,我们重复的给str1赋值,其实在内存中的变化如下右图:

Paste_Image.png

 从上图我们可以看出,str1在重复的初始化过程中,是因为str1中存储的元素地址由'hello world'的地址变成了'new hello world'的。

2.数据结构内部元素变化重对python语义引用的影响

Paste_Image.png

 当对列表中的元素进行一些增删改的操作的时候,是不会影响到lst1列表本身对于整个列表地址的,只会改变其内部元素的地址引用。可是当我们对于一个列表重新初始化(赋值)的时候,就给lst1这个变量重新赋予了一个地址,覆盖了原本列表的地址,这个时候,lst1列表的内存id就发生了改变。上面这个道理用在所有复杂的数据类型中都是一样的。

变量的赋值

Paste_Image.png

  我们刚刚已经知道,str1的再次初始化(赋值)会导致内存地址的改变,从上图的结果我们可以看出修改了str1之后,被赋值的str2从内存地址到值都没有受到影响。
  看内存中的变化,起始的赋值操作让str1和str2变量都存储了‘hello world’所在的地址,

重新对str1初始化,使str1中存储的地址发生了改变,指向了新建的值,此时str2变量存储的内存地址并未改变,所以不受影响。

2.复杂的数据结构中的赋值

刚刚我们看了简单数据类型的赋值,现在来看复杂数据结构变化对应内存的影响。

Paste_Image.png
上图对列表的增加修改操作,没有改变列表的内存地址,lst1和lst2都发生了变化。
对照内存图我们不难看出,在列表中添加新值时,列表中又多存储了一个新元素的地址,而列表本身的地址没有变化,所以lst1和lst2的id均没有改变并且都被添加了一个新的元素。

简单的比喻一下,我们出去吃饭,lst1和lst2就像是同桌吃饭的两个人,两个人公用一张桌子,只要桌子不变,桌子上的菜发生了变化两个人是共同感受的

初识拷贝

我们已经详细了解了变量赋值的过程。对于复杂的数据结构来说,赋值就等于完全共享了资源,一个值的改变会完全被另一个值共享。
  然而有的时候,我们偏偏需要将一份数据的原始内容保留一份,再去处理数据,这个时候使用赋值就不够明智了。python为这种需求提供了copy模块。提供了两种主要的copy方法,一种是普通的copy,另一种是deepcopy。我们称前者是浅拷贝,后者为深拷贝。
  深浅拷贝一直是所有编程语言的重要知识点,下面我们就从内存的角度来分析一下两者的区别。

1、什么是深浅拷贝 深拷贝和浅拷贝,python中一切皆对象,像数字,字符串,元祖,如果在内存中存储了这些元素,那么这块内存中的值是不可以被修改的,但是还存在一些可变对象,比如列表和字典,他们所占有的内存空间是可以修改的,有因为python中使用的是引用计数去节省内存。

首先我们定义一个列表并引用
list=[1,2,[1,2]]
list1=list
id(list) 140150690045832
id(list1) 140150690045832 

注:id函数的意思是返回对象object的标识符,标识符类型为整数,在同一个时间里所有对象的标识符是唯一的,
如果在不同生命周期的对象有可能有相同的标识符。 例如:我们把list中的第一个数改变的话我们发现list1也随之改变,

问什么会出现这种情况呢,这是因为python中使用的是引用计数去节省内存。
list[0]='a'
list['a',2,[1,2]]
list1['a',2,[1,2]] 

但是我们往往只想修改list而不改变list1,怎么实现呢我们可以通过切片拷贝
dellist1
list['b',2,[1,2]]
list1=list[:]#切片赋值
list1['b',2,[1,2]]
list[-1][0]='c'#将list[-1][0]修改为字符c
list['b',2,['c',2]]
list1['b',2,['c',2]] #我们发现虽然我们切片操作了, 但是对于里层的列表却没改变

总结一下:当你使用切片操作拷贝的时候,我们修改了外层的列表,外层不随之改变,但是 修改里层的子列表时,却会改变。 除此之外浅拷贝还有第二种方式,及插入copy模块copy模块实现浅拷贝 首先我们删除列表,并插入模块

dellist
dellist1
importcopy定义列表并对外层内层赋值
list=[1,2,[1,2]]
list1=copy.copy(list)#使用copy模块实现赋值
list[1,2,[1,2]]
list1[1,2,[1,2]]
list[-1][0]='a'#里层赋值
list[0]='b'#外层赋值 
list['b',2,['a',2]]
list1[1,2,['a',2]] #这里我们发现外层没有随之改变,但是里层却跟着变了,

这就是copy模块实现浅拷贝,但是我们想实现互不影响那我们使用深拷贝

3、深拷贝 使用deepcopy函数 首先我们删除list1并重新赋值

dellist1
list['b',2,['a',2]] 
list1=copy.deepcopy(list)
list['b',2,['a',2]]
list1['b',2,['a',2]]
list[0]='c'#对list[0]修改,修改的是外层
list[-1][0]='d' #对list[-1][0]修改,修改的是内层
list['c',2,['d',2]]
list1['b',2,['a',2]]#这里我们发现对list赋值后,list内层外层都没有随之改 变这就是深拷贝。 

4、总结:

浅拷贝:不会拷贝数据中的子对象切片拷贝,

importcopy copy.copy()

深拷贝:会拷贝数据中的子对象

importcopy.deepcopy
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • python的深浅拷贝,使用python的童鞋并不陌生,但是在这里面有几点需要注意的,我们忽略的点,在此总结一下,...
    KillerManA阅读 441评论 3 0
  • 在python中,对象赋值实际上是对象的引用。当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝...
    chen_000阅读 165评论 0 1
  • http://python.jobbole.com/85231/ 关于专业技能写完项目接着写写一名3年工作经验的J...
    燕京博士阅读 7,566评论 1 118
  • 地球是我们生存的星球,但还有多少人还在关心地球。滥用化学用品、大量砍伐数目、到处扔垃圾……使我们的地球妈妈已经受到...
    ssssssssena阅读 208评论 0 0
  • 这是 清水一点通 日更的第 320 篇,希望能打动到你。 30岁,对于一般男生来说是价值观固定,认知放大的分水岭,...
    清水一点通阅读 2,156评论 0 5