最佳答案
在深入研究 Python 的源代码之后,我发现它维护了一个从 int(-5)
到 int(256)
的 PyInt_Object
数组(@src/Objects/intoject.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
(实际上是在 ast_for_atom()
函数中执行的) ,但是它们之后会被合并。
我发现很难理解的来源在 PyAST_Compile
和 PyEval_EvalCode
,所以我在这里请求帮助,如果有人给我一个提示,我会很感激?