深入研究Python的源代码后,我发现它维护了一个PyInt_Object
s数组,范围从int(-5)
到int(256)
(@ src / Objects / intobject.c)
一个小实验证明了这一点:
>>> a = 1
>>> b = 1
>>> a is b
True
>>> a = 257
>>> b = 257
>>> a is b
False
但是,如果我在py文件中一起运行这些代码(或使用分号将它们结合在一起),结果将有所不同:
>>> a = 257; b = 257; a is b
True
我很好奇为什么它们仍然是同一对象,所以我深入研究了语法树和编译器,提出了下面列出的调用层次结构:
PyRun_FileExFlags()
mod = PyParser_ASTFromFile()
node *n = PyParser_ParseFileFlagsEx() //source to cst
parsetoke()
ps = PyParser_New()
for (;;)
PyTokenizer_Get()
PyParser_AddToken(ps, ...)
mod = PyAST_FromNode(n, ...) //cst to ast
run_mod(mod, ...)
co = PyAST_Compile(mod, ...) //ast to CFG
PyFuture_FromAST()
PySymtable_Build()
co = compiler_mod()
PyEval_EvalCode(co, ...)
PyEval_EvalCodeEx()
然后,我在PyInt_FromLong
之前/之后添加了一些调试代码PyAST_FromNode
,并执行了一个test.py:
a = 257
b = 257
print "id(a) = %d, id(b) = %d" % (id(a), id(b))
输出如下:
DEBUG: before PyAST_FromNode
name = a
ival = 257, id = 176046536
name = b
ival = 257, id = 176046752
name = a
name = b
DEBUG: after PyAST_FromNode
run_mod
PyAST_Compile ok
id(a) = 176046536, id(b) = 176046536
Eval ok
这意味着在这cst
对ast
变换,两个不同的PyInt_Object
s的创建(实际上它的真实执行的ast_for_atom()
功能),但他们后来合并。
我觉得很难理解的来源PyAST_Compile
和PyEval_EvalCode
,所以我在这里寻求帮助,如果有一个人给了一个暗示,我会感激?