预备知识一——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

python copy函数用法_Python深浅拷贝相关推荐

  1. python copy函数用法_python shutil模块函数copyfile和copy的区别

    展开全部 copyfile(src, dst) #src, dst 都需是文件名, 如果dst 存在或无权限,会抛出异常 copy(src, dst) #dst 可以是目录名. shutil.copy ...

  2. python所有函数用法_python函数用法总结

    空函数 如果想定义一个什么事也不做的空函数,可以用pass语句: def nop(): pass pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码 ...

  3. python自动复制输出_python 深浅拷贝集合

    一.深浅拷贝 1.浅拷贝,只会拷贝第一层 s = [1, 'ss', '小可爱'] s1=s.copy()print(s1) >>> [1, 'ss', '小可爱'] s = [1, ...

  4. python func函数用法_python函数局部变量用法实例分析

    本文实例讲述了python函数局部变量用法.分享给大家供大家参考.具体分析如下: 当你在函数定义内声明变量的时候,它们与函数外具有相同名称的其他变量没有任何关系,即变量名称对于函数来说是 局部 的.这 ...

  5. python func函数用法_Python常见内置高效率函数用法示例

    本文实例讲述了Python常见内置高效率函数用法.分享给大家供大家参考,具体如下: 1.  filter(function,sequence) 将sequence中的每个元素,依次传进function ...

  6. python itemgetter函数用法_Python itemgetter函数怎么用?

    Operator模块中也有一类函数可以作为条件过滤. 首先介绍 itemgetter 函数.假设定义了一个 f 函数,f = itemgetter(2),那么如果调用 f(r),实际会返回 r[2]. ...

  7. python pow函数用法_Python代码中pow()函数具有哪些功能呢?

    摘要: 下文讲述Python代码中pow()函数的功能说明,如下所示: pow函数功能说明 pow() 函数用于 计算 xy(x 的 y 次方) 的值 pow函数语法: import math mat ...

  8. python replace函数用法_Python实现的从右到左字符串替换方法示例

    本文实例讲述了Python实现的从右到左字符串替换方法.分享给大家供大家参考,具体如下: 一 . 前言 需要用到,但是发现python没有从右边开始替换的内置方法,默认的replace只是从左边开始, ...

  9. python所有函数用法_Python函数使用方法(高级用法)

    前面章节,已经介绍了 Python 函数的所有基本用法和使用注意事项.但是,Python 函数的用法还远不止此,Python 函数还支持赋值.作为其他函数的参数以及作为其他函数的返回值. 首先,Pyt ...

最新文章

  1. onSaveInstanceState与onRestoreInstance
  2. java线程同步的五种方法
  3. Intellij IDEA神器居然还有这些小技巧
  4. 阿里云常见问题及解决方案:
  5. boost / vs2017 编译 boost 1.68.0 的过程说明
  6. 左外连接的sql语句_Django数据库连接和使用原生sql语句
  7. Java与汽车_Java NIO:IO与NIO的区别
  8. 【程序员】保持一颗虚心好学的心态去敲代码
  9. aps后缀是什么文件_APS审核真的取消了么?
  10. 【SQL Server备份恢复】数据库恢复:对page header的恢复
  11. 程序猿爆笑选集(1)
  12. (16)VHDL实现半加器与全加器
  13. java基础循环 for 、switch 、while 、do while、
  14. mysql auto_inc_MySQL innodb_autoinc_lock_mode 详解
  15. SpannableString 给TextView添加不同的显示样式
  16. 安装terrasolid模块的“setup.exe”弹窗setup.inf not found
  17. 山寨google, 新做了1个网站 googler.cc ,做的很山寨 喜欢的朋友可以去看看哈
  18. html的页脚设计,如何单独设置页眉页脚
  19. 商业综合体能耗在线监测管理系统_商场管理平台
  20. 联想微型计算机如何设置u盘启动,联想电脑如何设置U盘启动?联想电脑bios设置U盘启动教程...

热门文章

  1. RT3070_STA_驱动移植文档
  2. 关于linux内核无法编译成模块的解决方法
  3. VMware linux 克隆机的配置
  4. android wheelview 字体颜色,百行代码实现Android WheelView
  5. 8086的两种工作模式_Buck变换器工作原理
  6. PyCharm中配置与PyQT5相关的External tools
  7. java中多线程编程案例_Java中多线程编程实战的实现线程_Java编程_Java程序员_课课家...
  8. 快手基于 Flink 的持续优化与实践
  9. mysql 内存越界_linux内存管理浅析
  10. 建立海盗的天堂:盗贼之海的AI设定(三):巨齿鲨、海怪和骷髅船的AI运行