一、python中的变量及引用
1.1 python中的不可变类型:

数字(num)、字符串(str)、元组(tuple)、布尔值(bool)
接下来我们讲完后你就懂了为什么它们是不可变对象了。
都知道python中一切都是对象,而变量就是这些对象的引用,什么意思呢
综合表述:
变量是一个系统表的元素,拥有指向对象的连接的空间

对象是被分配的一块内存,存储其所代表的值

引用是自动形成的从变量到对象的指针

特别注意: 类型属于对象,不是变量

>>> c = 17 #1 数字17就是一个对象,实实在在存在计算机内存中
>>> d = c #2 c 和 d 都是对象17的一个引用,c指向17,d也是
>>> id(c) #3
1462698960
>>> id(d) #4
1462698960

在#1 处我们定义了各一个变量c,c指向了17(把17赋值给c),对象17的一个引用c



然后在#2处,又定义了一个变量d ,把c赋值给了d,接着#3、#4查看了c、d的 id 相同,

发现是同一个对象(17),对象17的引用+1



引用:

对象17的引用现在有两个了

变量:

在内部,变量事实上是到对象内存空间的一个指针

1.2 python中内存回收机制

1.2.1 python本身是一门动态语言
与c/c++ /java不同,不需要事先定义变量开辟内存空间,然后给变量赋值,存储到变量的内存空间中。使用结束,当然也不需要你去手动调用析构函数释放内存了。
python会预先申请一部分内存空间,在运行时定义了变量-对象,根据对象确认它的type,将对象放到申请的内存中,python每过一段时间就来检查一次,当有对象的引用为0时,就回收这块内存,返还回先申请的内存空间,而不是计算机。这样避免了内存碎片过多问题。

1.2.2 怎么减少对象的引用

  1. 将变量引用指向其他对象
>>> c = 17
>>> d = c
>>> id(c) #1
1462698960
>>> id(d) #2
1462698960
>>> c = "yue" #3
>>> id(c) #4
612496081896
>>> d #5
17

可以看到#1、#2处c、d都还是对象17的引用,当#3处把变量c 指向新对象字符串"yue" 时,#4处发现变量c指向的对象id变了,的确不是17了,所以对象17的引用 -1 如下图

注意:这儿改变了c的引用,可是#5处d却没有跟着c变,还是对象17

同理当你再把d指向其他对象时,对象17的引用就减为零,当Python来检查时,就会回收这块内存了

2.删除变量(引用)

>>> del d
>>> d
Traceback (most recent call last):
File "<stdin>", line 1, in <modul
NameError: name 'd' is not defined

不啰嗦,这样对象17就彻底被删除了,上图时对象17只剩下一个变量引用d。

同理对于函数,定义函数时,函数名就是一个引用,当其他地方调用函数时,引用+1,调用结束 -1 。在函数的命名空间中可以查到这些,详情看我这篇文章

python的内存回收就到这儿:总结:回收机制为判断对象 引用是否为0,如果为零就回收内存到自己申请的内存空间,不是计算机硬盘。

1.3 再谈不可变类型

通过上面的式子和图理解我们也知道了,当定义变量为数字、字符串、tuple、布尔值时,这些变量所对应的对象在内存空间的值是不可改变了,你重新赋值,也只是把变量引用指向了另一个对象,id变了,本身那个对象是不可变的。

>>> a = (1, 'one')
>>> id(a)
612494666568 #1
>>> a[0] = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a[0]
1
>>> a = (2, 'two')
>>> id(a)
612494666824 #2 #---------------------------------------------
>>> a = 'findxgo' #3
>>> id(a)
612496082848
>>> a.replace('x','--X--') #4
'find--X--go'
>>> id(a) #5
612496082848
>>> a = a.replace('x', '-X-') #6
>>> id(a)
612496086704

在#3出定义了字符串a,#4处替换x,得到一新字符串,但是原字符串还是#5id没变,当#6把替换的字符串赋值给变量a,a的引用指向了替换后新字符串

二、python中的深浅Copy
2.1 共享引用

如图:指两个或多个变量指向同一个内存空间
![](https://images2018.cnblogs.com/blog/1226829/201808/1226829-20180804124229776-277665676.png)

如果删掉c后, 不会影响d

拷贝概念的引入就是针对:可变对象的共享引用潜在的副作用而提出的。

2.2 可变对象

2.2.1 指python中,存储在内存可以被修改的对象:列表、字典等
上面说的数字、字符串、元组等不可变类型,在你复制时也就是增加了一个引用,无法去改变内存的值。对对象的其中一个引用变量操作不会影响其他引用。
但是对于列表、字典:

>>> list_1 = [5, 2, 1]
>>> L2 = list_1 #1 将list_1赋值给L2
>>> list_1,L2
([5, 2, 1], [5, 2, 1])
>>> list_1[2] = '01314' #2 修改list_1 索引2处的值
>>> list_1,L2
([5, 2, '01314'], [5, 2, '01314'])

可以看到#1 上面定义一个列表,赋值给L2后,L2、list_1对应完全一样的值(列表)事实上,他两的确对应着一块内存,你可以自己去查id,是那块内存(列表)的两个引用

当你去在list_1,或者L2进行操作时,改变了对应内存的值,所以#2下面两个值都变了。python中同一块内存(对象)的不同引用改变对象所以引用都会被影响。

同理字典:通过自己哈希表将key计算后得到的内存地址就是存放value的地方,当你用如上同样的方式改变哪儿的值,所有引用都会被影响。

2.3 浅copy

上述的情况如果想避免,有两种方式,原理都一样:copy一份放到另一个内存,变成同样(value)的两个对象,当你修改其中一个时,另一个不会影响。
1、切片复制:完全切片

>>> list_1 = [5, 2, 1]
>>> L2 = list_1[:] #1 此处完全切片,复制
>>> list_1,L2
([5, 2, 1], [5, 2, 1])
>>> id(list_1) #2 查看id
612496051784
>>> id(L2) #3
612496051720

如上:#1处完全切片也可以L2 = list_1[0: -1]是一样的,#2,#3处可以看见,id不同,就不是同一个对象,只是里面的value相同而已

同理copy模块的copy方法,这是浅拷贝。

2.4 深copy

1. 深浅拷贝,即可用于序列,也可用于字典

>>> import copy

>>> dict_1 = {'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}

>>> D2 = copy.copy(dict_1)      #浅拷贝:只拷贝顶级的对象,也说:父级对象

>>> D3 = copy.deepcopy(dict_1)  #深拷贝:拷贝所有对象,顶级对象及其嵌套对象。或者说:父级对象及其子对象

>>> print("源:{0: ^18}\n浅拷贝:{1}\n深拷贝:{2}".format(id(dict_1),id(D2),id(D3)))
源: 37811303432
浅拷贝:37813197256
深拷贝:37813160264

2.改变源顶级对象,深浅拷贝不会变

>>> dict_1['copy'] = 'n_copy'
>>> dict_1;D2;D3
{'copy': 'n_copy', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}

3.改变源嵌套对象,浅拷贝变了,深拷贝不变

>>> dict_1['deepcopy'][1] = '嵌套层'
>>> dict_1;D2;D3
{'copy': 'n_copy', 'deepcopy': ['deep', '嵌套层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '嵌套层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}

这儿的浅拷贝,只拷贝了父级对象,在'deepcopy'对应的哪儿就是只拷贝了内存地址,而深拷贝还要去内存地址拷贝内容回来赋值

原理看到这儿,差不多也懂了,就不罗嗦了!

三、总结
  • 深浅拷贝都是对源对象的复制,占用不同的内存空间
  • 如果源对象只有一级目录的话,源做任何改动,不影响深浅拷贝对象
  • 如果源对象不止一级目录的话,源做任何改动,都要影响浅拷贝,但不影响深拷贝
  • 序列对象的切片其实是浅拷贝,即只拷贝顶级的对象

一个有意思的练习题

import copy
a = [1,2,3,[4,5],6]
b=a
c=copy.copy(a)
d=copy.deepcopy(a)
b.append(10)
c[3].append(11)
d[3].append(12)

a,b,c,d分别为什么?

答案我放评论

python 的内存回收,及深浅Copy详解的更多相关文章

  1. Python的深浅copy详解

    Python的深浅copy详解 目录 Python的深浅copy详解 一.浅copy的原理 1.1 浅copy的定义 1.2 浅copy的方法 二.深copy的原理 2.1 深copy的定义 2.2 ...

  2. 深浅copy详解

    一. 前言 在python中,对象的赋值和深浅copy,是有差异的.最终得的值也不同,下面我们就通过几个例子,来看下它们之间的区别. 二. 赋值 list2 = ["jack",2 ...

  3. JVM垃圾回收算法及回收器详解

    引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...

  4. 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS

    深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...

  5. 【python】redis基本命令和基本用法详解

    [python]redis基本命令和基本用法详解 来自http://www.cnblogs.com/wangtp/p/5636872.html 1.redis连接 redis-py提供两个类Redis ...

  6. Python中操作mysql的pymysql模块详解

    Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ...

  7. [转载]windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解

    windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解 http://shashanzhao.com/archives/832.html 虽然是中文字,但是理解起来还是很困难,什么叫工 ...

  8. 七牛云存储Python SDK使用教程 - 上传策略详解

    文 七牛云存储Python SDK使用教程 - 上传策略详解 七牛云存储 python-sdk 七牛云存储教程 jemygraw 2015年01月04日发布 推荐 1 推荐 收藏 2 收藏,2.7k  ...

  9. Python调用C/C++动态链接库的方法详解

    Python调用C/C++动态链接库的方法详解 投稿:shichen2014 这篇文章主要介绍了Python调用C/C++动态链接库的方法,需要的朋友可以参考下 本文以实例讲解了Python调用C/C ...

随机推荐

  1. mcelog用法详解

    手动启动mcelog方法: # mcelog --daemon Run mcelog in daemon mode, waiting for errors from the kernel. 后台服务启 ...

  2. 解决 win10 由于磁盘缓慢造成机器迟钝

    关闭 windows 的superfetch服务 建议禁止 superfetch服务: http://www.360quan.com/safe/6946.html 操作: http://jingyan ...

  3. SAP事物代码

    事物代码是SAP进入特定功能的快捷命令,如事物代码VA01能快速进入创建销售订单的页面,要浏览当前页面的事物代码,在状态栏右下角可以查看 快速导航事物代码 这类事物代码将功能相似的事物代码组合在一起, ...

  4. June 6. 2018 Week 23rd Wednesday

    You are confined only by the walls you build yourself. 限制你的只有你自己筑起的墙. From Andrew Murphy. Let's repe ...

  5. 【vue】使用localStorage解决vuex在页面刷新后数据被清除的问题

    通常,我们在使用vue编写页面时,会需要使用vuex在组件间传递(或者说共同响应)同一个数据的变化.例如:用户的登录信息. 下面,我们使用传递用户登录信息的例子来一步步解决这个问题. 首先,我们的第一 ...

  6. vue同一页面中拥有两个表单时,验证问题

    问题:如果vue的同一个页面拥有两个表单.验证第一个表单时没有通过就切换到第二个,那么第二个表单会出现验证错误的信息 我们可以通过为两个表单添加ref属性 之后在通过调用resetFields()方法 ...

  7. IO的详细解释:It's all about buffers: zero-copy, mmap and Java NIO

    There are use cases where data need to be read from source to a sink without modification. In code t ...

  8. centos7下kubernetes(6。运行应用)

    Deployment 从一个例子开始 kubectl run nginx-deployment --image=nginx:1.7.9 --replicas=2 kubectl get deploym ...

  9. -bash: _docker_machine_ps1: 未找到命令

    场景:在安装完docker-machine,设置docker-machine命令自动补齐的时候,出现以下错误: -bash: __docker_machine_ps1: 未找到命令 解决办法:在~/. ...

  10. java读取properties中文乱码

    1 确认properties文件的编码是utf-8 2 采用流的方式读取文件,设置编码为utf-8 public class ErrorCodeConfig { static Properties p ...