模块代码块(开始编译)
├─ 解析模块级语句(如x=10,直接生成字节码)
├─ 遇到class MyClass:(生成类code object外壳,暂不处理类体)
│ └─ 类代码块(搁置,等待模块级编译完成后处理)
└─ 模块级编译完成(模块code object生成)
类代码块(开始编译)
├─ 解析类体语句(如y=20,生成字节码)
├─ 遇到def my_func:(生成函数code object外壳,暂不处理函数体)
│ └─ 函数代码块(搁置,等待类体编译完成后处理)
└─ 类体编译完成(类code object生成)
函数代码块(开始编译)
├─ 解析函数体语句(如z=30、if块,生成完整字节码)
└─ 函数编译完成(函数code object生成)
关键: 每个代码块的编译会触发内层代码块的“搁置”,待外层编译完成后,再回头处理内层,形成“外层先定义、内层后实现”的递进顺序,这与“递归”的层级逻辑一致。
“递归”在编译原理中的本质:语法树的深度优先遍历
Python编译器基于语法树(Syntax Tree) 进行编译,语法树的结构是嵌套的(如模块→类→函数)。编译过程本质是对语法树的深度优先遍历:
先访问外层节点(模块),生成对应code object的框架;
遇到内层节点(类)时,先记录类定义,生成类code object的框架,再继续遍历类体中的节点(函数);
直到遍历到最内层节点(函数体语句)时,才生成具体的字节码,然后逐层返回,填充外层code object的细节。
code object的字段(如co_code、co_consts)中,co_code存储字节码指令,而内层代码块的字节码会作为外层code object的一部分被嵌套存储。例如:
◦ 模块code object的co_consts可能包含类code object;
◦ 类code object的co_consts可能包含函数code object;
◦ 函数code object的co_code包含具体执行的字节码。
总结:“递归”的核心是层级处理,而非重复操作