栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Python-解释器维护的整数缓存是什么?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python-解释器维护的整数缓存是什么?

Python会缓存范围内的整数

[-5, 256]
,因此可以预期该范围内的整数也相同。

你看到的是Python编译器在相同文本的一部分时优化了相同文字。

Python shell
中键入时,每行都是完全不同的语句,在不同的时刻进行了解析,因此:

>>> a = 257>>> b = 257>>> a is bFalse

但是,如果将相同的代码放入文件中:

$ echo 'a = 257> b = 257> print a is b' > testing.py$ python testing.pyTrue

每当解析器有机会分析使用文字的位置时(例如在交互式解释器中定义函数时),都会发生这种情况:

>>> def test():...     a = 257...     b = 257...     print a is b... >>> dis.dis(test)  20 LOAD_ConST    1 (257)   3 STORE_FAST    0 (a)  36 LOAD_ConST    1 (257)   9 STORE_FAST    1 (b)  4          12 LOAD_FAST     0 (a)  15 LOAD_FAST     1 (b)  18 COMPARE_OP    8 (is)  21 PRINT_ITEM 22 PRINT_newline         23 LOAD_ConST    0 (None)  26 RETURN_VALUE        >>> test()True>>> test.func_pre.co_consts(None, 257)

请注意,已编译的代码如何包含的单个常量257。

总之,Python字节码编译器无法执行大规模优化(如静态类型语言),但它的功能超出你的想象。这些事情之一是分析文字的用法并避免重复它们。

请注意,这与缓存无关,因为它也适用于没有缓存的浮点数:

>>> a = 5.0>>> b = 5.0>>> a is bFalse>>> a = 5.0; b = 5.0>>> a is bTrue

对于更复杂的文字,例如元组,它“不起作用”:

>>> a = (1,2)>>> b = (1,2)>>> a is bFalse>>> a = (1,2); b = (1,2)>>> a is bFalse

但是元组内部的文字是共享的:

>>> a = (257, 258)>>> b = (257, 258)>>> a[0] is b[0]False>>> a[1] is b[1]False>>> a = (257, 258); b = (257, 258)>>> a[0] is b[0]True>>> a[1] is b[1]True

关于为什么看到两个

PyInt_Object
被创建的原因,我猜想这样做是为了避免字面比较。例如,数字257可以用多个文字表示:

>>> 257257>>> 0x101257>>> 0b100000001257>>> 0o401257

解析器有两种选择:

在创建整数之前,将文字转换为某些通用基数,然后查看文字是否等效。然后创建一个整数对象。
创建整数对象,然后查看它们是否相等。如果是,则仅保留一个值并将其分配给所有文字,否则,你已经具有要分配的整数。

Python
解析器可能使用了第二种方法,该方法避免了重写转换代码,并且更易于扩展(例如,它也可以与
float
一起使用)。

读取

Python/ast.c
文件后,解析所有数字的函数是,该函数
parsenumber
调用
PyOS_strtoul
以获得整数值(对于整数),并最终调用
PyLong_FromString

    x = (long) PyOS_strtoul((char *)s, (char **)&end, 0);    if (x < 0 && errno == 0) {        return PyLong_FromString((char *)s,(char **)0,0);    }

正如你可以在这里看到解析器将不会检查是否已经找到与给定值的整数,所以这就是为什么你看到两个int对象被创建的,而这也意味着,我的猜测是正确的:解析器首先创建常数并且只有在此之后,才能优化字节码以将相同的对象用于相同的常量。

进行此检查的代码必须位于

Python/compile.c
或中
Python/peephole.c
,因为这些是将AST转换为字节码的文件。

特别是,该

compiler_add_o
功能似乎是执行此功能的人。中有此评论
compiler_lambda:

if (compiler_add_o(c, c->u->u_consts, Py_None) < 0)    return 0;

因此,似乎

compiler_add_o
将其用于为函数
/ ​​lambdas
等插入常量。该
compiler_add_o
函数将这些常量存储到
dict
对象中,然后立即将相等的常量放入同一插槽中,从而在最终字节码中生成单个常量。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/407576.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号