exec()执行多行字符串需缩进一致且风格统一,显式传入含__builtins__的命名空间才能正常使用内置函数,定义的函数仅存于该命名空间中。

exec() 执行多行字符串时,缩进必须一致
Python 的 exec() 不是简单拼接后运行,它会把传入的字符串当作完整模块或代码块解析。如果字符串里有 if、for 或函数定义,缩进不合法(比如混用空格和 Tab,或缩进层级断层),直接抛 IndentationError。
- 用三重引号包裹多行代码时,确保所有行缩进风格统一(推荐 4 空格)
- 避免从剪贴板直接粘贴带 IDE 自动缩进的代码——有些编辑器会在首行加空格,导致整个块偏移
- 调试技巧:先把字符串赋给变量,用
print(repr(code_str))看实际换行和空白符
命名空间传参不传 globals 就等于裸跑
exec() 默认使用调用处的 globals() 和 locals(),但 locals() 在函数内是只读副本,改了也影响不到外部变量。所以想让执行结果“写回去”,必须显式传入可变命名空间。
- 安全做法:传入一个干净的
dict作为globals,再单独传locals(可与globals相同) - 别写
exec(code, {}, {})—— 这会让__builtins__消失,连print都报NameError - 正确姿势:
ns = {'__builtins__': __builtins__}; exec(code, ns, ns),或者更省事:ns = {}; exec(code, ns)(Python 3.8+ 会自动补__builtins__)
exec() 里定义的函数无法直接调用?因为没进当前作用域
在 exec() 中用 def 声明的函数,只会存在于你传进去的那个命名空间字典里,不会自动变成当前模块的全局函数。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 想调用它,得从命名空间字典里取:
ns['my_func'](),而不是直接写my_func() - 如果代码里有
return,它不会返回值——exec()本身无返回值,所有产出都靠修改命名空间 - 注意闭包问题:动态生成的函数若引用了外层变量(比如循环变量
i),容易捕获到最终值而非当时值,和普通lambda陷阱一样
为什么 exec() 在某些环境里被禁用或失效
不是所有 Python 运行环境都允许 exec()。Jupyter Notebook 默认支持,但很多沙箱、在线评测系统、生产服务的容器镜像会删掉 __builtins__.exec 或限制 AST 解析。
立即学习“Python免费学习笔记(深入)”;
- 常见报错:
NameError: name 'exec' is not defined或TypeError: 'NoneType' object is not callable - 检查方式:
print(hasattr(__builtins__, 'exec')),或者直接dir(__builtins__)看有没有exec - 替代思路:如果只是要计算表达式,优先用
eval();如果要加载配置,考虑json或ast.literal_eval()更安全
__builtins__ 或误信 locals() 可写,是最常卡住人的地方。

















