详解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定时器(Timer)用法简单实例
Jun 04 Python
Python实现统计文本文件字数的方法
May 05 Python
Python基于回溯法子集树模板解决m着色问题示例
Sep 07 Python
python实现报表自动化详解
Nov 16 Python
python实现简易云音乐播放器
Jan 04 Python
Python 实现某个功能每隔一段时间被执行一次的功能方法
Oct 14 Python
Python多线程threading模块用法实例分析
May 22 Python
深入了解Python在HDA中的应用
Sep 05 Python
pytorch中nn.Conv1d的用法详解
Dec 31 Python
flask利用flask-wtf验证上传的文件的方法
Jan 17 Python
python如何从键盘获取输入实例
Jun 18 Python
Python的3种运行方式:命令行窗口、Python解释器、IDLE的实现
Oct 10 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
PHP一些有意思的小区别
2006/12/06 PHP
PHP学习资料汇总与网址
2007/03/16 PHP
js 页面输出值
2008/11/30 Javascript
jQuery判断checkbox(复选框)是否被选中以及全选、反选实现代码
2014/02/21 Javascript
jquery实现相册一下滑动两次的方法
2015/02/09 Javascript
JavaScript判断对象是否为数组
2015/12/22 Javascript
JavaScript中数组添加值和访问值常见问题
2016/02/06 Javascript
JavaScript如何实现跨域请求
2016/08/05 Javascript
for循环 + setTimeout 结合一些示例(前端面试题)
2017/08/30 Javascript
ES6中新增的Object.assign()方法详解
2017/09/22 Javascript
JS实现的全排列组合算法示例
2017/10/09 Javascript
详解JS数值Number类型
2018/02/07 Javascript
element-ui 表格实现单元格可编辑的示例
2018/02/26 Javascript
快速解决layui弹窗按enter键不停弹窗的问题
2019/09/18 Javascript
微信小程序实现页面浮动导航
2020/01/08 Javascript
js键盘事件实现人物的行走
2020/01/17 Javascript
Python文件路径名的操作方法
2019/10/30 Python
对python中arange()和linspace()的区别说明
2020/05/03 Python
Elasticsearch py客户端库安装及使用方法解析
2020/09/14 Python
pandas将list数据拆分成行或列的实现
2020/12/13 Python
HTML5 Canvas 破碎重组的视频特效的示例代码
2019/09/24 HTML / CSS
图片上传插件ImgUploadJS:用HTML5 File API 实现截图粘贴上传、拖拽上传
2016/01/20 HTML / CSS
利用HTML5 Canvas制作键盘及鼠标动画的实例分享
2016/03/15 HTML / CSS
前端实现弹幕效果的方法总结(包含css3和canvas的实现方式)
2018/07/12 HTML / CSS
爱尔兰家电数码商城:Currys PC World爱尔兰
2016/07/23 全球购物
逻辑链路控制协议
2016/10/01 面试题
法学毕业生自我鉴定
2013/11/08 职场文书
总经理职责
2013/12/22 职场文书
工程索赔意向书
2014/08/30 职场文书
党的群众路线教育实践活动通讯稿
2014/09/10 职场文书
党员干部学法用法心得体会
2016/01/21 职场文书
SQL Server——索引+基于单表的数据插入与简单查询【1】
2021/04/05 SQL Server
彻底理解golang中什么是nil
2021/04/29 Golang
MongoDB orm框架的注意事项及简单使用
2021/06/20 MongoDB
分析MySQL优化 index merge 后引起的死锁
2022/04/19 MySQL
MySQL 原理与优化之Update 优化
2022/08/14 MySQL