python 不可变量和可变量(稍微深入)
来源:互联网 发布:苹果手机游戏优化器 编辑:程序博客网 时间:2024/05/18 01:39
@ 摘要:
Python的数据类型涉及到2个大原则 即 可变和不可变,是否可变显然说的变量代表的内存空间里的值。
本文简要概述python3的 (python2版本好像更奇葩) 并且和Java的相关内容进行类比。
以源码为依据,从时间和空间出发猜测为什么会这么做。
@ 作者: http://blog.csdn.net/vincent_ceso
@ 声明:不保证正确:) 转载无需注明 就说是你写的。
>>作者:http://blog.csdn.net/vincent_ceso
Python的不可变量
>字符
>数值
>元组
[不可变量的描述]
引用->对象:
- 对于不可变量如果需要创建的对象的内容(value值)相同,则引用都指向同一个对象,不创建新的内存空间。
- 理论上因为定义了值是不可变的。所以如果大家都一样的值,那就指向同一份内存空间好了。显然这么节省内存,避免冗余。
- 但是实现的时候显然考虑到记录和维护这些变量。那么每次赋值的时候还涉及到一个查找是不是已经存在,引起了时间和空间的矛盾。实际上python实现的时候可是因地制宜的,会有很多的细节琐碎处。
#[demo1 数值(int float)]a = 10 #数值 但是是int 10b = 10 #数值 但是是int 10c = 10. #数值 但是是float 10.print(a is b) #True 说明内存是相同的空间 这就是不可变导致的a和b数值相同,那么a,b指向同一个内存空间。print(a == b) #True 数值相等print(a is c) #False 显然数值不同,那么指向内存空间不同print(a == c) #True 因为==是运算,即int==float 的不同类型元素涉及类型转换。#所以Python先把int变成float即再比较。显然是相同的a = 11 #修改值 值不同 那么就是新的内存空间了print(a is b) #False 显然数值不同,那么指向的内存空间不同'''琐碎处:python3 似乎没发现如下问题。python2 : 如果你的测试数值大于[-5,256]就发现出错。是版本问题。不同版本处理int的实现方式不同。 [小整数对象使用对象池技术]:Python直接将这些小范围的整数对应的PyIntObject缓存在内存中,其指针放在small_ints中。预先存储好了一堆小数值。 因为python是有一个smallint数组来维护的。相当于解释器的一个缓存,对于smallint,即[-5,256]范围,所以如果你的值在这个范围里,那就直接指向预先设好的这个内存空间。如果超出那么就是开辟新空间存储。 为什么? 因为维护这么一个smallint数组必须是高效的。首先因为维护和预先设定内存存储数据那就是内存的开销,而到时候new一个int对象还要涉及到查找是不是已存在于smallint里的CPU开销。 如果你经常使用1 2 3 这三个 那么显然就针对这三个维护起来很高效啊。但是实际中数值是很难预测的,即很难命中已缓存的。所以维护太多是毫无意义的。而且多了到时候你就要用个数字a++一下。结果人家先找到这个数字。找了10ms这么慢再返回。那岂不是还不如直接开辟的好。 时间和空间的协调。所以维护了一个小范围常用的的池子即可。'''
#[demo2 字符串]a = "cesto"b = "cesto"c = "XJ"print(a is b) #True 说明指向的内存是相同的空间 这就是不可变print(a == b) #True 数值相等print(a is c) #False 显然数值不同,那么指向的内存空间不同print(a == c) #False 值不同a = "XJ"print(a is b) #False 值不同 指向的内存空间不同print(a is c) #True 说明指向的内存是相同的空间 #说明没有新生成a 而是指向c指向的那个内存空间哦!!!'''【琐碎处】:如果测试数值相等,但是输出啊is b是False,还是版本问题。 因为字符串一般都是通过字典维护的,new一个记录下,下次如果是相同的那就直接指向相同内存空间不产生新的。 python3:实现了intern共享。 为啥? 因为字符串参与运算很少吧,存储的确很多。即字符串是一个存储为主导的。必然涉及到大量内存。所以节省内存是字符串高效的地方啊,所以我们舍弃时间追求空间。 python2里:没看过源码。似乎是有人说字符串很长很长的时候就无效。那么大概可以理解因为字符串那么太长涉及到的就是存储的压缩。导致维护的开销恒大,所以太长也就放弃了记录了。 '''
#[demo3 元组]a = (1,"cesto",[1]) #一个新的元组(1,"cesto")被a所指向b = (1,"cesto",[1]) #一个新的元组(1,"cesto")被b所指向print(a is b) #Flase 为什么?因为其实此时此刻产生的是俩个对象。没有实现intern机制print(a == b) #True 数值相等''' 即此时此刻是两个元素a和b,虽然他们的值相同,但是是俩个对象。而且这俩a和b是不可变的:即你修改他们只能是重新赋值,其实是指向了新的内存空间,而不能对原来指向的内存空间做出修改。原来的内存空间是还在的,然后很快就被GC掉。本质就是没实现Intern''''''【琐碎处】: 元组本身有很多不一样。就是因为元组的元素可以是任意的元素。即元素本身可以是不可变或者可变的。所以比较特殊。元组的不变就是说,凡是修改一个元组对象,必然是返回一个新的数组对象。而不可能是在原地址进行修改。 理论上应该和数值 字符串一样维护啊,但是没有? 为啥? 因为元组本身就没实现intern机制。其实本质元组是等价于C里的数组的。每次你new数组就是新创建。根本就没有维护和记录啊。 为啥不维护? 因为查找太慢啊。维护是为了避免冗余,但是相同的元组似乎出现的场景太少了吧那。 空间意义和时间意义都不大。那就不实现。'''#【看到一个以其昏昏,使人昭昭,强加附会的例子】a = (1) #这是不是一个元组?b = (1) print(a is b) # True 为什么?print(type(a)) # 因为(1)此时可不是元组 而是int'''认为上述例子可以反驳 元组的实现情况 '''a = (1,) #这才是一个元组b = (1,) print(a is b) # False 为什么?print(type(a)) # 因为(1,)此时是元组
[小结]
- 1.即如果不可变量的值相同,那么数值相同理论上完全指向同一个内存空间
- 2.所以如果有指针修改了大家都指向的这一块内存空间 那么引用他的全部变量的值就一次性都变了。
好在不支持指针,Python没有指针是避免了这个问题。- 3.这样的不可变变量就是: 数值 字符串 元组
- 4.数值 字符串 基本都是按照“值相等那就是指向同一个内存空间” 避免冗余。内存浪费。
因为实现了Intern机制。但是要注意是一定范围内才有效。- 5.其中元组比较特殊。只是保证了不可原地修改。但相等的元组不是指向同一个内存地址。
因为本质tuple没有实现intern机制
Python的可变量
>列表
>字典
>集合
[可变量的描述]
引用->对象:
- 对于可变量只要创建对象那就是本质是new一个新的内存空间,但是好处是能够修改。即修改对象值不会新开辟对象而是就是在原来内存空间改。
a=[1,2,3] b=[1,2,3] print(a is b ) #false 每次new新的,才不维护呢print(a==b) #true '''可变量和引用是相对应的,即使对象的内容相等,也是不同的对象,修改的时候,两个对象互不影响'''print(id(a)) #2810505330120a.append(4) # 修改值print(id(a)) #2810505330120 内存空间前后没变
阅读全文
0 0
- python 不可变量和可变量(稍微深入)
- python的不可变量和可变量
- python可变变量和不可变变量
- Python 可变变量与不可变变量
- python中的变量可变与不可变
- python 可变与不可变变量
- python可变对象和不可变对象
- python的可变和不可变对象
- Python-可变对象和不可变对象
- python变量赋值(可变与不可变)
- 【转载】python变量赋值(可变与不可变)
- python变量赋值(可变与不可变)
- python变量赋值(可变与不可变)
- Python基础:Python可变对象和不可变对象
- Python基础:Python可变对象和不可变对象
- python 可变数据和不可变数据解析
- python中数据类型(对象)的可变和不可变性
- python的可变类型和不可变类型
- 威左夫博弈
- 微信小程序之下拉加载和上拉刷新
- 大写金额转换成阿拉伯数字金额
- dubbo再学习
- 关于Eclipse/MyEclipsejava代码模板用法
- python 不可变量和可变量(稍微深入)
- BFC宽度自适应布局
- true launch bar 和 editplus
- spring 事务管理——回滚之service层(事务控制层)代码互调
- BZOJ 3994 莫比乌斯反演
- Java集合Hashtable源码解析
- Kafka术语解释
- Android 应用保活笔记
- spring jdbcTemplate增删改查(转)