前言

本文除"总结"外,其余均为认识过程;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. gin框架中集成casbin-权限管理

    概念 权限管理几乎是每个系统或者服务都会直接或者间接涉及的部分. 权限管理保障了资源(大部分时候就是数据)的安全, 权限管理一般都是和业务强关联, 每当有新的业务或者业务变化时, 不能将精力完全放在业 ...

  2. Python定制化天气预报消息推送

    sansui-Weather 代码码云 介绍 定制化天气预报消息推送(练手小脚本) Python脚本实现天气查询应用,提醒她注意保暖! 功能介绍 天气信息获取 当天天气信息提示 第二天天气信息提示 网 ...

  3. 为什么 Redis 的查询很快, Redis 如何保证查询的高效

    Redis 如何保证高效的查询效率 为什么 Redis 比较快 Redis 中的数据结构 1.简单动态字符串 SDS 对比 c 字符串的优势 SDS可以常数级别获取字符串的长度 杜绝缓冲区溢出 减少修 ...

  4. Java多线程专题2: JMM(Java内存模型)

    合集目录 Java多线程专题2: JMM(Java内存模型) Java中Synchronized关键字的内存语义是什么? If two or more threads share an object, ...

  5. numpy 矩阵在作为函数参数传递时的奇怪点

    numpy 矩阵在作为函数参数传递时的奇怪点 import numpy as np class simpleNet: def __init__(self): self.W = np.array([1, ...

  6. Java当中“+=”和“=+”的区别

    "+="会自动类型强制转换! 隐含了一个强制类型转换! 一 string a1 = "9"; int a2 = 10; a1+=a2; a1=a1+a2; 不会 ...

  7. Arduino+ESP32 之 驱动GC9A01圆形LCD(一),基于Arduino_GFX库

    最近买了一块圆形屏幕,驱动IC是GC9A01,自己参考淘宝给的stm32的驱动例程, 在ubuntu下使用IDF开发ESP32,也在windows的vscode内安装IDF开发ESP32,虽然都做到了 ...

  8. 跨域 CORS 详解 (转)

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从 ...

  9. js正则表达式 未提交进行验证

    转载请注明来源:https://www.cnblogs.com/hookjc/ function SetInputMust(){  /*var varr=idstr.split(','); idstr ...

  10. Java内存分析简单介绍

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11904422.html Java内存分析简单介绍: 1. # 设置内存溢出时自动生成堆内存快照 ...