eval() 既慢又危险,因其每次调用需全程重新解析执行且默认共享作用域,易被利用执行任意代码;ast.literal_eval() 仅安全解析静态字面量,不求值、不调用、不访问属性,异常统一为 valueerror。

eval() 为什么既慢又危险
它不是“有点风险”,而是根本设计上就不该用于不可信输入——每次调用都要从字符串重新做词法分析、语法解析、AST 构建、字节码生成,全程跳过编译期优化;同时默认共享当前作用域,__builtins__、全局变量、甚至 type().__subclasses__() 都可能被恶意字符串触达。
常见错误现象:看似无害,实则已失守
你以为删掉 __builtins__ 就安全了?错。攻击者可以用 ().__class__.__mro__[1].__subclasses__() 找回 os 模块,再调用 system。你用 eval("{'a': 1 + 2}") 测试没问题,但用户传 "__import__('os').system('id')" 时,进程已经执行了系统命令。
- 报
SecurityError?那是运行时主动拦截,更多时候它静默执行 - 本地测试通过 ≠ 上线安全:本地没权限删文件,不代表服务器上不能
- 配置文件里写
"[1, 2, 3] + [4]",eval()会算,ast.literal_eval()直接抛ValueError—— 这就是安全边界的体现
ast.literal_eval() 的真实能力边界
它不是“eval 的安全版”,而是完全不同的东西:只认静态字面量,不求值、不调用、不访问属性。能 parse 的只有:"123"、"'hello'"、"[1, 'x', {'y': True}]"、"(1, 2)"、"{'k': None}"。连 "1.5 * 2" 或 "b'bytes'"(旧版本)都会失败。
- JSON 格式要先转:把
true→True,null→None - 异常类型变了:
eval()抛SyntaxError/NameError,ast.literal_eval()只抛ValueError(和极少见的MemoryError) - 别指望它做计算——需要算术表达式,就用
simpleeval,并显式传names={"x": 5},绝不传globals()
真正容易被忽略的点
很多人换掉 eval() 后仍出问题,是因为没意识到:输入格式必须是合法 Python 字面量,不是 JSON;异常处理逻辑要重写;ast.literal_eval() 不支持单字符字符串如 "a"(缺引号就报错),也不支持尾部逗号或注释——这些细节在配置加载或 API 入参场景里极易翻车。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











