python新手学习可变和不可变对象


Posted in Python onJune 11, 2020

python中有可变对象和不可变对象,可变对象:list,dict.不可变对象有:int,string,float,tuple.

python不可变对象

int,string,float,tuple

先来看一个例子

def int_test(): 
 i = 77
 j = 77
 print(id(77))     #140396579590760
 print('i id:' + str(id(i)))  #i id:140396579590760
 print('j id:' + str(id(j)))  #j id:140396579590760
 print i is j     #True
 j = j + 1
 print('new i id:' + str(id(i))) #new i id:140396579590760
 print('new j id:' + str(id(j))) #new j id:140396579590736
 print i is j     #False
 
if __name__ == '__main__':
 int_test()

有i和j俩个变量的值为77,通过打印77的ID和变量i,j在内存中的id我们得知它们都是指向同一块内存。所以说i和j都是指向同一个对象的。然后我们修改j的值,让j的值+1.按道理j修改之后应该i的值也发生改变的,因为它们都是指向的同一块内存,但结果是并没有。因为int类型是不可变类型,所有其实是j复制了一份到新的内存地址然后+1,然后j又指向了新的地址。所以j的内存id发生了变化。

内存分配情况如下:

python新手学习可变和不可变对象

有i和j俩个变量的值为77,通过打印77的ID和变量i,j在内存中的id我们得知它们都是指向同一块内存。所以说i和j都是指向同一个对象的。然后我们修改j的值,让j的值+1.按道理j修改之后应该i的值也发生改变的,因为它们都是指向的同一块内存,但结果是并没有。因为int类型是不可变类型,所有其实是j复制了一份到新的内存地址然后+1,然后j又指向了新的地址。所以j的内存id发生了变化。

内存分配情况如下:

def dict_test():
 a = {}
 b = a
 print(id(a))
 a['a'] = 'hhhh'
 print('id a:' + str(id(a)))
 print('a:' + str(a))
 print('id b:' + str(id(b)))
 print('b:' + str(b))if __name__ == '__main__':
 dict_test()

运行结果如下:

140367329543360
id a:140367329543360
a:{'a': 'hhhh'}
id b:140367329543360
b:{'a': 'hhhh'}

可以看到a最早的内存地址id是140367329543360 然后把a赋值给b其实就是让变量b的也指向a所指向的内存空间。然后我们发现当a发生变化后,b也跟着发生变化了,因为list是可变类型,所以并不会复制一份再改变,而是直接在a所指向的内存空间修改数据,而b也是指向该内存空间的,自然b也就跟着改变了。

内存变化如下:

python新手学习可变和不可变对象

python函数的参数传递

由于python规定参数传递都是传递引用,也就是传递给函数的是原变量实际所指向的内存空间,修改的时候就会根据该引用的指向去修改该内存中的内容,所以按道理说我们在函数内改变了传递过来的参数的值的话,原来外部的变量也应该受到影响。

但是上面我们说到了python中有可变类型和不可变类型,这样的话,当传过来的是可变类型(list,dict)时,我们在函数内部修改就会影响函数外部的变量。而传入的是不可变类型时在函数内部修改改变量并不会影响函数外部的变量,因为修改的时候会先复制一份再修改。下面通过代码证明一下:

def test(a_int, b_list):
 a_int = a_int + 1
 b_list.append('13')
 print('inner a_int:' + str(a_int))
 print('inner b_list:' + str(b_list))
if __name__ == '__main__':
 a_int = 5
 b_list = [10, 11]
 test(a_int, b_list)
 print('outer a_int:' + str(a_int))
 print('outer b_list:' + str(b_list))

运行结果如下:

inner a_int:6
inner b_list:[10, 11, '13']
outer a_int:5
outer b_list:[10, 11, '13']

答案显而易见啦,经过test()方法修改后,传递过来的int类型外部变量没有发生改变,而list这种可变类型则因为test()方法的影响导致内容发生了改变。

总结:

在很多的其他语言中在传递参数的时候允许程序员选择值传递还是引用传递(比如c语言加上*号传递指针就是引用传递,而直接传递变量名就是值传递),而python只允许使用引用传递,但是它加上了可变类型和不可变类型,让我们感觉有点混乱了。听说python只允许引用传递是为方便内存管理,因为python使用的内存回收机制是计数器回收,就是每块内存上有一个计数器,表示当前有多少个对象指向该内存。每当一个变量不再使用时,就让该计数器-1,有新对象指向该内存时就让计数器+1,当计时器为0时,就可以收回这块内存了。

知识点扩展:

Python可变对象与不可变对象原理解析

原理

可变对象:list dict set

不可变对象:tuple string int float bool

1. python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。实际上,这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象的引用,就能修改对象的原始值——相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象的引用,就不能直接修改原始对象——相当于通过“传值'来传递对象。

2. 当人们复制可变对象时,就复制了可变对象的引用,如果改变引用的值,则修改了原始的参数。

3. 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。

到此这篇关于python新手学习可变和不可变对象的文章就介绍到这了,更多相关python可变对象和不可变对象内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
pycharm 使用心得(七)一些实用功能介绍
Jun 06 Python
python实现用于测试网站访问速率的方法
May 26 Python
使用Python求解最大公约数的实现方法
Aug 20 Python
不要用强制方法杀掉python线程
Feb 26 Python
PyQt5每天必学之日历控件QCalendarWidget
Apr 19 Python
Python 实现两个服务器之间文件的上传方法
Feb 13 Python
Python拼接字符串的7种方式详解
Mar 19 Python
解决django无法访问本地static文件(js,css,img)网页里js,cs都加载不了
Apr 07 Python
音频处理 windows10下python三方库librosa安装教程
Jun 20 Python
记一次python 爬虫爬取深圳租房信息的过程及遇到的问题
Nov 24 Python
Python批量将csv文件转化成xml文件的实例
May 10 Python
Python使用海龟绘图实现贪吃蛇游戏
Jun 18 Python
基于Keras 循环训练模型跑数据时内存泄漏的解决方式
Jun 11 #Python
什么是python的id函数
Jun 11 #Python
Keras:Unet网络实现多类语义分割方式
Jun 11 #Python
Pycharm中配置远程Docker运行环境的教程图解
Jun 11 #Python
Keras 快速解决OOM超内存的问题
Jun 11 #Python
python3.6.8 + pycharm + PyQt5 环境搭建的图文教程
Jun 11 #Python
使用keras实现孪生网络中的权值共享教程
Jun 11 #Python
You might like
php缓存技术介绍
2006/11/25 PHP
PHP中使用FFMPEG获取视频缩略图和视频总时长实例
2014/05/04 PHP
PHP ajax 异步执行不等待执行结果的处理方法
2015/05/27 PHP
php时间函数用法分析
2016/05/28 PHP
用cookies实现的可记忆的样式切换效果代码下载
2007/12/24 Javascript
javascript数组快速打乱重排的方法
2014/01/02 Javascript
javascript实现节点(div)名称编辑
2014/12/17 Javascript
每天一篇javascript学习小结(Function对象)
2015/11/16 Javascript
JS弹出窗口插件zDialog简单用法示例
2016/06/12 Javascript
bootstrap折叠调用collapse()后data-parent不生效的快速解决办法
2017/02/23 Javascript
AngularJS中使用ngModal模态框实例
2017/05/27 Javascript
nodejs遍历文件夹下并操作HTML/CSS/JS/PNG/JPG的方法
2018/11/01 NodeJs
浅谈JavaScript面向对象--继承
2019/03/20 Javascript
微信小程序实现购物车代码实例详解
2019/08/29 Javascript
[00:31]DOTA2荣耀之路7:Miracle-空血无敌斩
2018/05/31 DOTA
[48:51]完美世界DOTA2联赛PWL S2 Magma vs InkIce 第一场 11.28
2020/12/02 DOTA
Python字符遍历的艺术
2008/09/06 Python
用pywin32实现windows模拟鼠标及键盘动作
2014/04/22 Python
利用Python实现简单的相似图片搜索的教程
2015/04/23 Python
socket + select 完成伪并发操作的实例
2017/08/15 Python
浅谈解除装饰器作用(python3新增)
2018/10/15 Python
Python图像滤波处理操作示例【基于ImageFilter类】
2019/01/03 Python
详解python--模拟轮盘抽奖游戏
2019/04/12 Python
Python 如何提高元组的可读性
2019/08/26 Python
Python线程协作threading.Condition实现过程解析
2020/03/12 Python
Selenium及python实现滚动操作多种方法
2020/07/21 Python
python里glob模块知识点总结
2021/01/05 Python
Pandas之缺失数据的实现
2021/01/06 Python
使用HTML5里的classList操作CSS类
2016/06/28 HTML / CSS
韩国CJ食品专卖网:CJonmart
2016/09/11 全球购物
德国Discount-Apotheke中文官网:DC德式康线上药房
2020/02/18 全球购物
世界经理人咨询有限公司面试
2014/09/23 面试题
Linux如何修改文件和文件夹的权限
2012/06/27 面试题
2014国庆节演讲稿:祖国在我心中(400字)
2014/09/25 职场文书
《浅水洼里的小鱼》教学反思
2016/02/16 职场文书
利用Selenium添加cookie实现自动登录的示例代码(fofa)
2021/05/08 Python