前言

本文除"总结"外,其余均为认识过程;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. 安卓开发之intent

    两个活动之间的跳转要通过intent来进行,intent跳转分为隐式的和显示的. 首先xml中定义Button,通过按下按钮实现回调,在回调函数中进行相应intent设置. <Button an ...

  2. java接口应用

    1 package face_09; 2 /* 3 * 笔记本电脑使用. 4 * 为了扩展笔记本的功能,但日后出现什么功能设备不知道. 5 * 6 * 定义了一个规则,只要日后出现的设备都符合这个规则 ...

  3. vue开源项目有点全

    目录 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 UI组件 element ★31142 - 饿了么出品的Vue2的web UI工具套件 Vux ★14104- 基于Vue和 ...

  4. 字的研究(2)Fonttools-字体文件的解析

    前言 本文主要介绍如果使用Python第三方库fontTools对TrueType字体文件(指使用TrueType描述轮廓的OpenType字体文件)的解析.修改和创建等操作. fontTools简介 ...

  5. Ansible架构

  6. 男孩和女孩(二)-->相识

    转载请注明来源:https://www.cnblogs.com/hookjc/ 那天是男孩的十九岁生日:男孩还是像平常一样,一大早就起来了(快七点了).一切都是那么的平常,直到第一节课下课,男孩的同窗 ...

  7. 长时间不操作Navicat或Putty会断线?

    问题描述 今天发现只要一直不使用Putty,发现就会"卡住",还有Navicat连接数据库也有类似问题. 问题分析 Linux或者数据库都想节省连接资源呗. 问题解决 那就隔一段时 ...

  8. Mac 使用自带php和Apache 安装配置Xdebug 开启本地调试模式

    Mac 安装配置php xdebug 本地调试 0.原理图 https://paper.seebug.org/308/ 测试demo构建方法 新建空白项目,目录选择Apache默认项目目录 1.下载x ...

  9. war3 Game

    转载请注明来源:https://www.cnblogs.com/hookjc/ //位置结构.x,y不多说,unknown是3F800000.浮点数1.0?? struct Pos {   DWORD ...

  10. win8.1/2012R2上面安装flash debugger

    1.开启windows桌面体验 a. Launch Power Shell b. Run command "add-WindowsFeature Desktop-Experience&quo ...