详解Python小数据池和代码块缓存机制


Posted in Python onApril 07, 2021

前言

本文除"总结"外,其余均为认识过程;3.7.5;这部分官方文档不知道在哪里找,目前没有找到,有谁知道的可以麻烦留言吗? 谢谢了!

总结:

如果在同一代码块下,则采用同一代码块下的缓存机制;
如果是不同代码块,则采用小数据池的驻留机制;
需要注意的是,交互式输入时,每个命令都是一个代码块;

实现 Intern 保留机制的方式非常简单,就是通过维护一个字符串储蓄池,这个池子是一个字典结构,编译时,如果字符串已经存在于池子中就不再去创建新的字符串,直接返回之前创建好的字符串对象,
如果之前还没有加入到该池子中,则先构造一个字符串对象,并把这个对象加入到池子中去,方便下一次获取;

长度为0与1的字符串一定会被驻留;
字符串驻留发生在程序编译时;
被驻留的字符串必须由 ASCll 字母, 数字以及下划线组成;

1.代码块的缓存机制

Python 程序是由代码块构造的。块是一个 Python 程序的文本,它是作为一个单元执行的。
代码块:一个模块, 一个函数, 一个类, 一个文件等都是一个代码块;
交互方式:在 cmd 中进入 Python 解释器里面,输入的每一条命令都是一个代码块;

Python 在执行同一个代码块的初始化对象的命令时,会检查其值是否存在,如果存在,会将其重用;
满足代码块的缓存机制则它们在内存中只存在一个,即:id相同;
代码块的缓存机制的适用范围: int(float),str,bool;

int(float): 任何数字在同一代码块下都会复用;
bool: True 和 False 在字典中会以 1,0 方式存在,并且复用;
str:同一代码块中,值相同的字符串在内存中只存在一个:

s1 = 'janes@!#*ewq'
s2 = 'janes@!#*ewq'
print(s1 is s2)	 # True 

a1 = 'janes45613256132!@#$%#^%@$%' * 1
b1 = 'janes45613256132!@#$%#^%@$%' * 1
print(a1 is b1) # True

s1 = 'hah_' * 6
s2 = 'hah_' * 6
print(s1 is s2) # True

2.小数据池

Python 自动将 -5~256 的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象;
Python会将满足一定规则的字符串在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象;
bool 值就是 True,False,无论你创建多少个变量指向 True,False,它在内存中都只存在一个;

小数据池也是只针对 int(float),str,bool;
小数据池是针对不同代码块之间的缓存机制;

# cmd, -5~256 的小整数虽然不在同一代码块中, 但是它们适用小数据池机制
>>>a = 245
>>>b = 245
>>>a is b # True
# 长度为0与1的字符串一定会被驻留;
# 字符串驻留发生在程序编译时;
# 被驻留的字符串必须由 ASCll字母, 数字以及下划线组成;
>>>s1 = '@'
>>>s2 = '@'
>>>s1 is s2 # True

>>>s1 = ''
>>>s2 = ''
>>>s1 is s2 # True

>>>s1 = 'a_b_c'
>>>s2 = 'a_b_c'
>>>s1 is s2 # True

>>>s1 = 'a b_c'
>>>s2 = 'a b_c'
>>>s1 is s2 # False

>>>s1 = 'a_b_c' * 1
>>>s2 = 'a_b_c' * 1
>>>s1 is s2 # True

>>>s1 = 'abd_d23' * 3
>>>s2 = 'abd_d23' * 3
>>>s1 is s2 # True

>>>a, b = "some_thing!", "some_thing!"
>>>a is b # False

>>>a, b = "some_thing", "some_thing"
>>>a is b # True
a1 = 1000
b1 = 1000
a1 is b1 # True

class C1(object): 
   a = 100
   b = 100
   c = 1000
   d = 1000
 
 
class C2(object):
   a = 100
   b = 1000

print(C1.a is C1.b)  # True
print(C1.a is C2.a)  # True
print(C1.c is C1.d)  # True
print(C1.c is C2.b)  # False

3.优缺点

优点:值相同的字符串的(比如标识符),直接从池里拿来用,避免频繁的创建和销毁,提升效率,节约内存;

缺点:拼接字符串、对字符串修改之类的影响性能;
因为是不可变的,所以对字符串修改不是 inplace 就地操作,要新建对象,这也是为什么拼接多字符串的时候不建议用 + 而用 join();
join() 是先计算出所有字符串的长度,然后一一拷贝,只 new 一次对象;

小整数对象池

为避免整数频繁申请和销毁内存空间,python 使用了小整数对象池,Python 对小整数的定义是 [-5, 256] ,这些整数对象是提前建立好的,不会被垃圾回收;
一个 Python 程序中,无论这个整数处于 LEGB 中哪个位置,所有位于这个范围内的整数使用的都是同一个对象;

# 3.7.5, ipython7.18.1
a = -5
b = -5
a is b # True

a = -6
b = -6
a is b # False

a = 256
b = 256
a is b # True

a = 257
b = 257
a is b # Flase

大整数对象池

cmd 终端中,大整数每赋值一次,每次的大整数都会重新创建,Pycharm 中,每次运行时,所有代码都加载到内存中,属于一个整体,所以这个时候会有一个大整数对象池处于一个代码块的大整数是同一个对象;
c 和 d 处于一个代码块,而 C1.b 和 C2.b 分别有自己的代码块,所以不相等;

# cmd 终端
a = 1000
b = 1000
a is b # False
--------------------
class C1(object): 
   a = 100
   b = 100
   c = 1000
   d = 1000
 
 
class C2(object):
   a = 100
   b = 1000

print(C1.a is C1.b)  # True
print(C1.a is C2.a)  # True
print(C1.c is C1.d)  # True ?? 难道 cmd 中也有大整数池 ?? 类加载的时候是在一块内存中,同值同地址 ?? 
print(C1.c is C2.b)  # False

# pycharm 等编辑器中
a = 1000
b = 1000
a is b # True
--------------------
class C1(object): 
   a = 100
   b = 100
   c = 1000
   d = 1000
 
 
class C2(object):
   a = 100
   b = 1000

print(C1.a is C1.b)  # True
print(C1.a is C2.a)  # True
print(C1.c is C1.d)  # True
print(C1.c is C2.b)  # False

字符串驻留机制

  Python 解释器为了提高字符串使用的效率和使用性能,编译时,使用了 intern(字符串驻留)技术来提高字符串效率,什么是 intern 机制?即值同样的字符串对象仅仅会保存一份,放在一个字符串储蓄池中,是共用的,当然,肯定不能改变,这也决定了字符串必须是不可变对象(整数类型也是不可变对象)??,浮点数就不行 ;

简单原理:

  实现 Intern 保留机制的方式非常简单,就是通过维护一个字符串储蓄池,这个池子是一个字典结构,编译时,如果字符串已经存在于池子中就不再去创建新的字符串,直接返回之前创建好的字符串对象,如果之前还没有加入到该池子中,则先构造一个字符串对象,并把这个对象加入到池子中去,方便下一次获取。;
  但是,解释器内部对intern 机制的使用策略是有考究的,有些场景会自动使用 intern ,有些地方需要通过手动方式才能启动,看下面几个常见情景:

# cmd 中浮点数没有被缓存
a = 1.0
b = 1.0
a is b # False

# cmd 中并非全部的字符串都会采用intern机制; 仅 包括下划线、数字、字母的字符串才会被 intern--类标识符
s1="hello"
s2="hello"
s1 is s2 # True

# 如果有空格,默认不启用intern机制
s1="hell o"
s2="hell o"
s1 is s2 # False

s1 = "hell!*o"
s2 = "hell!*o"
print(s1 is s2) # False

# 如果一个字符串长度超过20个字符,不启动intern机制 -- 看网上很多都是这么写的, 不超过二十个就为真,但是我在自己 3.7/8.5 版本上试了一下,发现好像没有限制,不知道是 Python 更新了,还是什么问题……
s1 = "a" * 20
s2 = "a" * 20
s1 is s2 # True

s1 = "a" * 21
s2 = "a" * 21
s1 is s2 # True

s1 = "ab" * 10
s2 = "ab" * 10
s1 is s2 # True

s1 = "ab" * 11
s2 = "ab" * 11
s1 is s2 # True

# 'kz' + 'c' 编译时已经变成 'kzc',而 s1 + 'c' 中 s1 是变量, 会在运行时进行拼接,所以没有被intern?
'kz' + 'c' is 'kzc' # True

s1 = 'kz'
s2 = 'kzc'
s1+'c' is 'kzc' # False

# pycharm 等编辑器中,只要是同一个字符串,都为 True,并不用是下划线、数字、字母的字符串
s1 = "hell o"
s2 = "hell o"
print(s1 is s2) # True

s1 = "hell!*o"
s2 = "hell!*o"
print(s1 is s2) # True

s1 = "a" * 20
s2 = "a" * 20
print(s1 is s2) # True

s1 = "a" * 21
s2 = "a" * 21
print(s1 is s2) # True

s1 = "ab" * 10
s2 = "ab" * 10
print(s1 is s2) # True

s1 = "ab" * 11
s2 = "ab" * 11
print(s1 is s2) # True

'kz' + 'c' is 'kzc' # True

s1 = 'kz'
s2 = 'kzc'
s1+'c' is 'kzc' # False

# 编辑器中,float 也被缓存了
a = 1.0
b = 1.0
a is b

以上就是详解Python 小数据池和代码块缓存机制的详细内容,更多关于Python 小数据池和代码块缓存机制的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python下如何让web元素的生成更简单的分析
Jul 17 Python
python str与repr的区别
Mar 23 Python
Python实现的简单dns查询功能示例
May 24 Python
Python实现基于多线程、多用户的FTP服务器与客户端功能完整实例
Aug 18 Python
解决Python中回文数和质数的问题
Nov 24 Python
如何通过Django使用本地css/js文件
Jan 20 Python
Python semaphore evevt生产者消费者模型原理解析
Mar 18 Python
Python selenium模拟手动操作实现无人值守刷积分功能
May 13 Python
完美解决Django2.0中models下的ForeignKey()问题
May 19 Python
Python中的With语句的使用及原理
Jul 29 Python
python 实现朴素贝叶斯算法的示例
Sep 30 Python
python机器学习Github已达8.9Kstars模型解释器LIME
Nov 23 Python
浅谈Python列表嵌套字典转化的问题
Apr 07 #Python
python pyhs2 的安装操作
Apr 07 #Python
python3 sqlite3限制条件查询的操作
Apr 07 #Python
python实现高效的遗传算法
解决hive中导入text文件遇到的坑
Apr 07 #Python
python - asyncio异步编程
Apr 06 #Python
python - timeit 时间模块
Apr 06 #Python
You might like
ASP和PHP实现生成网站快捷方式并下载到桌面的方法
2014/05/08 PHP
PHP中把对象数组转换成普通数组的方法
2015/07/10 PHP
PHP编写登录验证码功能 附调用方法
2016/05/19 PHP
PHP生成腾讯云COS接口需要的请求签名
2018/05/20 PHP
js jquery做的图片连续滚动代码
2008/01/06 Javascript
JavaScript 应用技巧集合[推荐]
2009/08/30 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
2014/01/06 Javascript
javascript计算星座属相(十二生肖属相)示例代码
2014/01/09 Javascript
跟我学习javascript的作用域与作用域链
2015/11/19 Javascript
ASP.NET jquery ajax传递参数的实例
2016/11/02 Javascript
自己封装的一个简单的倒计时功能实例
2016/11/23 Javascript
javascript输出AscII码扩展集中的字符方法
2016/12/26 Javascript
JavaScript数据结构之双向链表定义与使用方法示例
2017/10/27 Javascript
使用nodeJs来安装less及编译less文件为css文件的方法
2017/11/20 NodeJs
jsonp跨域及实现百度首页联想功能的方法
2018/08/30 Javascript
NodeJs生成sitemap站点地图的方法示例
2019/06/11 NodeJs
JS中比Switch...Case更优雅的多条件判断写法
2019/09/05 Javascript
python3序列化与反序列化用法实例
2015/05/26 Python
Python2.x利用commands模块执行Linux shell命令
2016/03/11 Python
对tensorflow 的模型保存和调用实例讲解
2018/07/28 Python
python实现海螺图片的方法示例
2019/05/12 Python
Python如何使用turtle库绘制图形
2020/02/26 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
Python如何读写字节数据
2020/08/05 Python
HTML5打开本地app应用的方法
2016/03/31 HTML / CSS
Allen Edmonds官方网站:一家美国优质男士鞋类及配饰制造商
2019/03/12 全球购物
数控专业大学生的自我鉴定
2013/11/13 职场文书
银行实习生的自我评价
2014/01/13 职场文书
学习十八大报告感言
2014/02/04 职场文书
《寓言两则》教学反思
2014/02/27 职场文书
企业活动策划方案
2014/06/02 职场文书
护士辞职信怎么写
2015/02/27 职场文书
反腐倡廉影片观后感
2015/06/08 职场文书
会议室使用管理制度
2015/08/06 职场文书
2016关于军训的心得体会
2016/01/11 职场文书
如何设置多台电脑共享打印机?多台电脑共享打印机的方法
2022/04/08 数码科技