@
python的整数重用机制
大体可以分为两部分:
small_ints
链表small_ints内保存着一定范围的小整数。当有变量引用了范围内的整数时,就会直接引用此中的地址,而非开辟新地址来存储数据。
这一范围可以通过下列代码来查看:
z = []
for i in range(-1000, 1000):
for j in range(-1000, 1000):
if id(i) == id(j):
z.append(i)
print([z[0], z[-1]])
python3.8.3得出的结果是[-5,256]。
也就是说,当以‘=’形式来给变量a、b赋范围内值时,id(a)==id(b)。
代码块
代码块是程序的一个最小的基本执行单位,一个模块文件、一个函数体、一个类、交互式命令中的单行代码都叫做一个代码块。
Python内部为了进一步提高性能,凡是在一个代码块中创建的整数对象,如果值不在small_ints缓存范围之内,但在同一个代码块中已经存在一个值与其相同的整数对象了,那么就直接引用该对象,否则创建一个新的对象出来。
需要注意的是,在small_ints范围外的负数并不适用这一规则。(范围内的负数浮点数同样不适用)
问题一:为什么在vscode中运行代码,得到了不符的结果?
下面放一张全图
问题二:在问题一存在的基础上,为什么能测得[-5,256]这一范围?
其他图片
vscode已安装的扩展
settings.json
后语
之前接触到整数缓存时曾做过测试,的确与介绍相符。但是,近期却发现自己测试出了相反的结果,一直不明白哪里出了问题,因此发到网上来。如有人能指出,不胜感激。
附带ID为“发霉的宅大人”帮忙提供的版本相关源码
#ifndef NSMALLPOSINTS
#define NSMALLPOSINTS 257
#endif
#ifndef NSMALLNEGINTS
#define NSMALLNEGINTS 5
#endif
static PyObject *
get_small_int(sdigit ival)
{
PyObject *v;
assert(-NSMALLNEGINTS <= ival && ival < NSMALLPOSINTS);
v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];
Py_INCREF(v);
#ifdef COUNT_ALLOCS
if (ival >= 0)
_Py_quick_int_allocs++;
else
_Py_quick_neg_int_allocs++;
#endif
return v;
}
2021-1-4
昨天卸载并重新安装了新版本的python、vscode,情况依旧没有改变。
测试小整数缓存表范围,ok(与之前一样)。
测试256地址,在不同代码块内保持一致,但每次都不一样。
测试-6地址,每次都不一样,但在不同代码块内保持一致。
2021-1-5
在“发霉的宅大人”的建议下,使用IDLE进行测试,以下为测试结果:
使用python解释器进行测试(不懂得怎么在定义函数时换行,暂时没找到教程,因此使用时尝试了多次,代码格式有没有问题……),以下为测试结果:
显然,256在不同代码块处于相同的地址中,而257则在不同代码中呈现出了两处地址。这对我来说无疑是个好消息。
我曾以为,python中的小整数缓存表都存储在固定的地址之中。在直接使用python解释器运行代码没问题的情况下,我重新取得了256的地址:
256的地址和上面256的地址并不相同,看样子python会在每次代码运行前为处于[-5,256]区间的小整数重新分配地址。
新的问题
将上述问题综合一下,本文的主要问题变成:
“为什么vscode、IDLE二者和python解释器运行同一代码会出现不同的结果?是什么导致了这一区别?”
2021-1-7