前言

本文除"总结"外,其余均为认识过程;3.7.5;

总结:

如果在同一代码块下,则采用同一代码块下的缓存机制;

如果是不同代码块,则采用小数据池的驻留机制;

需要注意的是,交互式输入时,每个命令都是一个代码块;

实现 Intern 保留机制的方式非常简单,就是通过维护一个字符串储蓄池,这个池子是一个字典结构,编译时,如果字符串已经存在于池子中就不再去创建新的字符串,直接返回之前创建好的字符串对象;

如果之前还没有加入到该池子中,则先构造一个字符串对象,并把这个对象加入到池子中去,方便下一次获取;

长度为0与1的字符串一定会被驻留;

字符串驻留发生在程序编译时;

不同代码块中,被驻留的字符串必须由 ASCll 字母, 数字以及下划线组成;

字符串的长度限制问题目前没有发现,就是没有发现超过 20 之后就不行了;

1.代码块的缓存机制

Python 程序是由代码块构造的。块是一个 Python 程序的文本,它是作为一个单元执行的。

代码块:一个模块, 一个函数, 一个类, 一个文件等都是一个代码块;交互方式输入的每个命令都是一个代码块;

交互方式:就是在 cmd 中进入 Python 解释器里面,每一条指令都是一个代码块;

Python 在执行同一个代码块的初始化对象的命令时,会检查其值是否存在,如果存在,会将其重用;

满足代码块的缓存机制则它们在内存中只存在一个,即:id相同;

代码块的缓存机制的适用范围: int(float),str,bool;

int(float): 任何数字在同一代码块下都会复用;

bool: True 和 False 在字典中会以 1,0 方式存在,并且复用;

str:同一代码块中,值相同的字符串在内存中只存在一个:

a1 = 1000
b1 = 1000
a1 is b1 # True f1 = 100.0
f2 = 100.0
print(f1 is f2) # True 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,str,bool;

小数据池是针对不同代码块之间的缓存机制;

# cmd, -5~256 的小整数虽然不在同一代码块中, 但是它们适用小数据池机制
>>>a = 245
>>>b = 245
>>>a is b # True >>>f1 = 100.0
>>>f2 = 100.0
>>>print(f1 is f2) # False
# 长度为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
3.试一试
a1 = 1000
b1 = 1000
print(a1 is b1) # True f1 = 100.0
f2 = 100.0
print(f1 is f2) # True class C1(object):
f = 10.0
a = 100
b = 100
c = 1000
d = 1000
s = 'skj' class C2(object):
f = 10.0
a = 100
b = 1000
s = 'skj' print(C1.s is C2.s) # True
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
print(C1.f is C2.f) # False
4.优缺点

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

缺点:拼接字符串、对字符串修改之类的影响性能;

   因为是不可变的,所以对字符串修改不是 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

参考:

https://www.zhihu.com/question/29945705 python里的怪问题

https://www.pianshen.com/article/9128116263/ python-小数据池,代码块深入剖析

https://www.dazhuanlan.com/2020/01/16/5e1f70e908538/ cpython 中的 string interning

Python 小数据池和代码块缓存机制的更多相关文章

  1. Python小数据池,代码块

    今日内容一些小的干货 一. id is == 二. 代码块 三. 小数据池 四. 总结 python小数据池,代码块的最详细.深入剖析   一. id is == 二. 代码块 三. 小数据池 四. ...

  2. python 小数据池,代码块, is == 深入剖析

    python小数据池,代码块的最详细.深入剖析   一. id is == 二. 代码块 三. 小数据池 四. 总结 一,id,is,== 在Python中,id是什么?id是内存地址,那就有人问了, ...

  3. python小数据池,代码块知识

    一.什么是代码块? 根据官网提示我们可以获知: A Python program is constructed from code blocks. A block is a piece of Pyth ...

  4. python小数据池,代码块的最详细、深入剖析

    代码块: Python程序是由代码块构造的.块是 一个python程序的文本,他是作为一个单元执行的. 代码块:一个模块,一个函数,一个类,一个文件等都是一个代码块. 而作为交互方式输入的每个命令都是 ...

  5. python小数据池,代码块深入剖析

    小数据池 目的:缓存我们字符串,整数,布尔值.在使用的时候不需要创建更多的对象 缓存:int,str,bool int:缓存范围-5~256 str:    1.长度小于等于1,直接缓存 2.长度大于 ...

  6. 五.python小数据池,代码块的最详细、深入剖析

    一,id,is,== 在Python中,id是什么?id是内存地址,那就有人问了,什么是内存地址呢? 你只要创建一个数据(对象)那么都会在内存中开辟一个空间,将这个数据临时加在到内存中,那么这个空间是 ...

  7. 百万年薪python之路 -- 小数据池和代码块

    1.小数据池和代码块 # 小数据池 -- 缓存机制(驻留机制) # == 判断两边内容是否相等 # a = 10 # b = 10 # print(a == b) # is 是 # a = 10 # ...

  8. python基础之小数据池、代码块、编码和字节之间换算

    一.代码块.if True: print(333) print(666) while 1: a = 1 b = 2 print(a+b) for i in '12324354': print(i) 虽 ...

  9. python基础之小数据池、代码块、编码

    一.代码块.if True: print(333) print(666) while 1: a = 1 b = 2 print(a+b) for i in '12324354': print(i) 虽 ...

随机推荐

  1. Java高效开发-常用idea插件

    这里推荐几个常用的idea插件,可以大大提高开发的效率 所使用的idea版本为 2021.2.3 1.Jrebel and Xrebel for IntelliJ Jrebel用于热部署,避免频繁重启 ...

  2. ESP32S2小项目-FM-网络时钟/电台-Arduino开发环境

    ESP32S2小项目,FM,网络时钟/电台,Arduino开发环境 效果展示 @ 目录 ESP32S2小项目,FM,网络时钟/电台,Arduino开发环境 效果展示 开机动画: 网络时钟: FM模块: ...

  3. python16day

    昨日回顾 自定义模块 模块的两种执行方式:脚本方式.调用方式 name 模块导入的方式 相对导入 random:获取随机数相关 今日内容 常用模块的介绍 time:和时间相关 datetime os ...

  4. 学习Java第9天

    今天所作的工作: 反射,枚举类型与泛型 明天工作: 1.线程 2.网络通信 所遇到的问题及解决方法: 反射基本思想,泛型类似于类模板. 理解反射太难了,转悠了好半天,关键是理解反射的思想,才容易学.

  5. window-server 服务器解决远程连接

    mstsc 连接远程服务器,出现黑屏的情况: 解决方案: 运行 -> 输入gpedit.msc,进入组策略 -> 计算机配置 -> 管理模板 -> Windows组件 -> ...

  6. X000011

    P1890 gcd区间 \(\gcd\) 是满足结合律的,所以考虑用 ST 表解决 时间复杂度 \(O((n\log n+m)\log a_i)\) 考虑到 \(n\) 很小,你也可以直接算出所有的区 ...

  7. markdown常见问题

    图片的引用问题: ![image](./images/git命令.png) 为啥不显示图片?????? 解答:图片路径不支持中文 斜体跟加粗 *强调* 或者 _强调_ (示例:斜体) **加重强调** ...

  8. iOS中属性 (nonatomic, copy, strong, weak)的使用 By hL

    以下内容来自Stackflow的详解 1.Nonatomicnonatomic is used for multi threading purposes. If we have set the non ...

  9. iOS加载Gif图片的N种方式 By-H罗

    1.系统UIImageView 多张图片组成动画 /** * UIImageView 动画 * Memory-23M */ -(void)gifPlay1 { // NSArray *array=@[ ...

  10. 「2022」打算跳槽涨薪,必问面试题及答案 -- ECMAScript 篇

    起点低怕什么,大不了加倍努力.人生就像一场马拉松比赛,拼的不是起点,而是坚持的耐力和成长的速度.只要努力不止,进步也会不止. 1.ECMAScript 与 JavaScript 的关系? ECMA(E ...