python解释器的作用是什么_Python-解释器维护的整数缓存是什么?

小编典典

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

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

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

>>> a = 257

>>> b = 257

>>> a is b

False

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

$ echo 'a = 257

> b = 257

> print a is b' > testing.py

$ python testing.py

True

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

>>> def test():

... a = 257

... b = 257

... print a is b

...

>>> dis.dis(test)

2 0 LOAD_CONST 1 (257)

3 STORE_FAST 0 (a)

3 6 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_code.co_consts

(None, 257)

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

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

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

>>> a = 5.0

>>> b = 5.0

>>> a is b

False

>>> a = 5.0; b = 5.0

>>> a is b

True

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

>>> a = (1,2)

>>> b = (1,2)

>>> a is b

False

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

>>> a is b

False

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

>>> 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可以用多个文字表示:

>>> 257

257

>>> 0x101

257

>>> 0b100000001

257

>>> 0o401

257

解析器有两种选择:

在创建整数之前,将文字转换为某些通用基数,然后查看文字是否等效。然后创建一个整数对象。

创建整数对象,然后查看它们是否相等。如果是,则仅保留一个值并将其分配给所有文字,否则,你已经具有要分配的整数。

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:

/* Make None the first constant, so the lambda can't have a

docstring. */

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

return 0;

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

2020-02-10

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值