Python3中为何在函数内部执行exec会失败?
为什么Python3中在函数内部执行exec会导致外部无法访问变量?
咱们先还原一下你遇到的问题场景:当你在主程序里直接执行exec('A = 10')时,能正常打印A;但把这段exec逻辑放到函数里执行后,外部调用print(A)就会抛出NameError,说A未定义。
问题复现代码
def execfunction(icode): print('code inside execfunction => %s' %(icode)) exec(icode) option = int(input("0 - for running inside function, 1 - for running in main programa: ")) print('option = %d' %(option)) code = 'A = 10' if (option == 1): exec(code) else: execfunction(code) print(A)
运行结果对比
------- 输入选项1 - exec代码执行成功 --------
0 - 在函数内运行,1 - 在主程序运行:1
option = 1
10
------- 输入选项0 - 函数内exec代码未执行成功 ----
0 - 在函数内运行,1 - 在主程序运行:0
option = 0
code inside execfunction => A = 10
Traceback (most recent call last):
File "myexec.py", line 19, in
print(A)
NameError: name 'A' is not defined
核心原因:Python3中exec的命名空间规则
Python3对exec的命名空间处理有明确的区分:
- 主程序环境:主程序的命名空间就是全局命名空间(
globals()),直接调用exec(code)时,默认会把变量写入全局命名空间,所以外部能直接访问A。 - 函数内部环境:函数有自己独立的局部命名空间(
locals()),默认情况下exec(icode)会把变量写入这个局部命名空间,但有两个关键限制:- Python函数的局部变量是编译时静态确定的,exec动态创建的变量不会被函数的字节码解释器识别为合法的局部变量,哪怕你在函数内部尝试访问
A也会报错。 - 函数的局部命名空间在函数执行完毕后会被销毁,即使变量被写入了局部空间,外部也根本无法访问。
- Python函数的局部变量是编译时静态确定的,exec动态创建的变量不会被函数的字节码解释器识别为合法的局部变量,哪怕你在函数内部尝试访问
解决方法
根据你的需求,有两种常见的处理方式:
1. 让exec直接操作全局命名空间
修改函数内的exec调用,显式指定globals()作为命名空间,这样变量会直接写入全局空间,外部就能访问:
def execfunction(icode): print('code inside execfunction => %s' %(icode)) # 指定globals参数,让exec使用全局命名空间 exec(icode, globals()) option = int(input("0 - for running inside function, 1 - for running in main programa: ")) print('option = %d' %(option)) code = 'A = 10' if (option == 1): exec(code) else: execfunction(code) print(A) # 现在输入0也能正常输出10
2. 自定义命名空间,避免污染全局
如果不想污染全局命名空间,可以创建一个专属字典作为exec的命名空间,执行完毕后返回需要的变量:
def execfunction(icode): print('code inside execfunction => %s' %(icode)) # 创建自定义命名空间 custom_namespace = {} exec(icode, globals(), custom_namespace) # 返回需要的变量 return custom_namespace.get('A') option = int(input("0 - for running inside function, 1 - for running in main programa: ")) print('option = %d' %(option)) code = 'A = 10' if (option == 1): exec(code) print(A) else: A = execfunction(code) print(A) # 同样能正常输出10
内容的提问来源于stack exchange,提问作者Marco Aurélio Falcão
相关产品推荐
相关产品推荐

