在深入研究 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
toast
变换的过程中,PyInt_Object
创建了两个不同的s(实际上是在ast_for_atom()
函数中执行的),但是后来又合并了。
我发现很难理解 and 中的来源PyAST_Compile
,PyEval_EvalCode
所以我在这里寻求帮助,如果有人提供提示,我将不胜感激?