Python编译含相互调用函数的AST时出现NameError问题求助
问题分析与解决
问题原因
你遇到的NameError本质是Python的名字作用域静态分析和exec()的命名空间规则共同导致的:
- Python函数在编译阶段会静态分析内部引用的名字,
fn里的fn_2会被标记为全局名字; - 当在函数
main内部直接调用exec()时,默认会使用main的局部命名空间,而fn_2被定义在这个局部命名空间中,不属于全局命名空间; - 因此
fn执行时会去全局命名空间查找fn_2,自然找不到。
解决方案
给exec()传入一个独立的字典作为全局命名空间,这样生成的所有函数都会被存入这个字典,函数内部的全局引用会指向该命名空间,相互调用就能正常工作:
def main(): str = """ def fn_2(): print("got so far") def fn(input): fn_2() fn("abc") """ # 创建独立的命名空间字典 exec_namespace = {} mod = compile(str, "testing", 'exec') # 将命名空间传入exec exec(mod, exec_namespace) if __name__ == "__main__": main()
补充说明
你第二个测试案例能运行,是因为原始文件中定义了全局的fn_2,exec()里的fn调用的是这个全局版本,而非你在字符串中定义的fn_2——这也是为什么注释掉字符串里的fn定义后还能运行(此时调用的fn应为你之前代码中定义的全局fn,案例代码可能存在笔误,但核心逻辑是全局命名空间的fn_2被成功找到)。
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

