python 的内存回收,及深浅Copy详解

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

数字(num)字符串(str)元组(tuple)布尔值(bool<True,False>)
接下来我们讲完后你就懂了为什么它们是不可变对象了。
都知道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
1226829-20180804102452096-1601909326.png
然后在#2处,又定义了一个变量d ,把c赋值给了d,接着#3、#4查看了c、d的 id 相同,
发现是同一个对象(17),对象17的引用+1
1226829-20180804104055864-1991516796.png
引用:
对象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
1226829-20180804112102206-166989152.png

同理当你再把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 共享引用

如图:指两个或多个变量指向同一个内存空间
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的地方,当你用如上同样的方式改变哪儿的值,所有引用都会被影响。
1226829-20180804162738243-2076986743.png

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分别为什么?
答案我放评论

转载于:https://www.cnblogs.com/shiqi17/p/9417663.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/353133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

不是技术牛人,如何拿到国内IT巨头的Offer

不久前&#xff0c;byvoid面阿里星计划的面试结果截图泄漏&#xff0c;引起无数IT屌丝的羡慕敬仰。看看这些牛人&#xff0c;NOI金牌&#xff0c;开源社区名人&#xff0c;三年级开始写Basic...在跪拜之余我们不禁要想&#xff0c;和这些牛人比&#xff0c;作为绝大部分技术屌丝…

layui列表筛选列_Shopify搜索产品并筛选产品列表功能介绍

搜索产品并筛选产品列表 您的所有产品都列在 Shopify 的产品区域中。每个页面列出 50 种产品。要整理产品列表&#xff0c;并在跨多个页面的列表中查找产品&#xff0c;您可以对列表进行排序、搜索和筛选。默认情况下&#xff0c;产品列表按产品名称的字母顺序(从 A 到 Z)进行排…

远程调用 quartz_如何远程管理Quartz

远程调用 quartz选项1&#xff1a;JMX 许多人问他们是否可以通过JMX管理Quartz&#xff0c;但我不确定为什么Quartz doc甚至不会提及它。 是的&#xff0c;您可以使用quartz.properties的以下命令启用石英中的JMX org.quartz.scheduler.jmx.export true之后&#xff0c;您可以…

DOM解析器

1.DOM标准 DOM&#xff08;Document Object Model&#xff0c;文档对象模型&#xff09;是W3C制定的一套规范标准&#xff0c;即规定了解析文件的接口。各种语言可以按照DOM规范去实现这些接口&#xff0c;给出解析文件的解析器。 各种基于DOM规范解析器必须按照DOM规范在内…

批量打印pdf并合并_批量打印CAD图(无删减版)

前面两期小编出的PDF教程想必用了的人都觉得还不错吧&#xff1f;(此处应有掌声)上一期提到的CAD批量打印今天放出来了&#xff0c;擦亮眼睛往下看很多时候大批量的一堆图纸要输出&#xff0c;比如下面这个当然这批图纸并不多&#xff0c;也只是局部的&#xff0c;通常一个项目…

expect详解及自动登录脚本的实现

expect可以让一些交互的任务自动完成&#xff0c;我们可以将一些交互过程写入脚本&#xff0c;ssh登录就是一个简单的实现&#xff0c;下面将介绍expect的用法。 1 安装 yum install -y expect 2 语法介绍 expect - send 这两个指令会配合使用&#xff0c;当expect接收到一个和…

极端懒惰:使用Spring Boot开发JAX-RS服务

我认为可以公平地说&#xff0c;作为软件开发人员&#xff0c;我们一直在寻找编写较少代码的方法&#xff0c;这些方法可以自动完成或不能自动完成更多工作。 考虑到这一点&#xff0c;作为Spring产品组合的骄傲成员的Spring Boot项目破坏了传统方法&#xff0c;极大地加快了并…

透明怎么弄_最新版微信如何设置透明背景?这样设置,效果令人惊喜

微信叒更新了&#xff0c;你的微信有更新吗&#xff1f;听说这次更新是安卓端的先更新&#xff0c;苹果端的还不能更新。今天小编要跟大家分享的是新版微信应该如何设置透明背景&#xff0c;不清楚微信透明背景长什么样子的&#xff1f;没关系&#xff0c;给你看看设置透明背景…

QueryRunner使用

在相继学习了JDBC和数据库操作之后&#xff0c;我们明显感到编写JDBC代码并非一件轻松的事儿。为了帮助我们更高效的学习工作&#xff0c;从JDBC的繁重代码中解脱出来&#xff0c;老佟给我们详尽介绍了一个简化JDBC操作的组件——DBUtils。我们今天主要学习了它所提供的两个类和…

基于vue的UI框架集锦(移动端+pc端)

1. vonic 一个基于 vue.js 和 ionic 样式的 UI 框架&#xff0c;用于快速构建移动端单页应用&#xff0c;很简约&#xff0c;是我喜欢的风格 star 2.3k 中文文档 在线预览 2.vux 基于WeUI和Vue(2.x)开发的移动端UI组件库 star 10k 基于webpackvue-loadervux可以快速开发移动端页…

com技术内幕 代码_CFan科学院:零门槛极速抠图技术探秘

将照片中的人或物从背景中分离出来&#xff0c;俗称抠图。要实现完美的抠图&#xff0c;没有一定的PS(Photoshop)基础是根本无法实现的&#xff0c;不过现在有个名为Remove.bg的网站&#xff0c;号称5秒钟就可以完成复杂的抠图&#xff0c;彻底将抠图难度降到了零门槛&#xff…

关于级联删除和级联修改

曾经因为级联删除的问题浪费了N多时间&#xff0c;顾此在这里写下小小心得&#xff0c;供大家借鉴。在数据库分别建立表t_food&#xff08;菜单&#xff09;和表t_book(订单)&#xff0c;如下所示&#xff1a;t_food:————————————————————————————…

python:数据库连接操作入门

模块 1 import pymssql,pyodbc 模块说明 pymssql和pyodbc模块都是常用的用于SQL Server、MySQL等数据库的连接及操作的模块&#xff0c;当然一些其他的模块也可以进行相应的操作&#xff0c;类似adodbapi、mssql、mxODBC等&#xff0c;我们在实际用的时候选择其中一个模块就好&…

java面试题:集合_Java:选择正确的集合

java面试题:集合这是在您的应用程序中选择Set &#xff0c; List或Map的正确实现的快速指南。 最好的通用或“主要”实现可能是ArrayList&#xff0c;LinkedHashMap和LinkedHashSet。 它们的整体性能更好&#xff0c;除非您需要其他实现提供的特殊功能&#xff0c;否则应使用它…

c:forEach

简介 <c:forEach>为循环控制&#xff0c;它可以将集合(Collection)中的成员循序浏览一遍。运作方式为当条件符合时&#xff0c;就会持续重复执行<c:forEach>的本体内容。 语法 语法1&#xff1a;迭代一集合对象之所有成员 <c:forEach [var"varName"] …

b500k带开关电位器内部构造_R138带开关大功率大电流电位器 B10K B500K

全阻值 :500Ω-1MΩ全阻值公差:20%阻抗特性型式:A,B,C,D杂音:Less than 100mV at 20 mmc.绝缘阻抗:More than 10MΩat DC 250V耐电压:1 minute at AC 250V残留阻值:Term.1~2:Less than 10Ω Term.2~3:Less than 10Ω同步误差(双联):-40dB~0dB3dB额定电压B线性:10mm,15mm:AC 100…

Java 8:将匿名类转换为Lambda表达式

将匿名类&#xff08;实现一种方法&#xff09;重构为lambda表达式&#xff0c;可使您的代码更简洁明了。 例如&#xff0c;这是Runnable及其lambda等效项的匿名类&#xff1a; // using an anonymous class Runnable r new Runnable() {Overridepublic void run() {System.o…

如何去掉a标签的下划线

首先来了解下<a>标签的一些样式&#xff1a; <a>标签的伪类样式 一组专门的预定义的类称为伪类&#xff0c;主要用来处理超链接的状态。超链接文字的状态可以通过伪类选择符&#xff0b;样式规则来控制。伪类选择符包括&#xff1a; 总: a 表示所有状态下的连接 …

Android.os.SystemClock

https://www.linuxidc.com/Linux/2011-11/48325p2.htm 文档中对System.currentTimeMillis()进行了相应的描述&#xff0c;就是说它不适合用在需要时间间隔的地方&#xff0c;如Thread.sleep, Object.wait等&#xff0c;因为可以通过System.setCurrentTimeMillis来改变它的值。要…

批量修改数据_#泰Q头条#065期 四步搞定Excel表中的批量数据修改

『闻道有先后 术业有专攻』又到每周五我们Offcie小课堂时间&#xff0c;每周学一点儿&#xff0c;知识从未如此简单&#xff0c;也真诚的希望各位能在留言板写下你们宝贵的建议&#xff0c;给您带来更具价值的分享。这期跟大家带来的Excel表数据整理功能——统一数值变动的实用…