eval存在严重安全风险,禁止用于解析用户输入;应使用ast.literal_eval处理Python字面量字符串,或json.loads处理标准JSON字符串。

eval 会执行任意代码,别用它解析用户输入
很多人想把 JSON 格式字符串或字典字符串转成 Python 对象,第一反应是 eval。但它根本不是“安全转换函数”,而是 Python 解释器入口——传进去 "__import__('os').system('rm -rf /')" 这种字符串,它真会执行。
常见错误现象:eval("{ 'a': 1 }") 看似能跑通,但只要字符串里带变量名、函数调用、甚至注释,就可能报错或失控。比如 eval("{'x': __builtins__}") 直接泄露内置对象。
使用场景仅限:你完全控制输入源(如配置文件硬编码、测试数据),且明确需要动态执行逻辑——这种需求本身就很罕见。
ast.literal_eval 是唯一推荐的字符串转字典方案
ast.literal_eval 只允许解析最基础的字面量:数字、字符串、元组、列表、字典、布尔值和 None。它不走 Python 解析器,而是直接遍历 AST 节点,天然免疫代码注入。
立即学习“Python免费学习笔记(深入)”;
实操建议:
- 始终用
ast.literal_eval替代eval处理用户提交的字典/列表字符串 - 输入必须是合法 Python 字面量格式,比如
"{'key': 'value'}"或"[1, 2, {'x': True}]";JSON 格式的双引号字符串({"key": "value"})会报SyntaxError - 遇到
ValueError: malformed node or string,大概率是用了双引号、尾随逗号、或 NaN/Infinity 等非字面量值
示例:
import ast
s = "{'name': 'alice', 'scores': [95, 87]}"
data = ast.literal_eval(s) # ✅ 安全成功
JSON.loads 更适合接口返回的字符串,但格式要求更严
如果你拿到的是标准 JSON(比如 API 返回的 {"name": "alice", "scores": [95, 87]}),json.loads 比 ast.literal_eval 更合适:性能略好、错误信息更明确、支持 Unicode 和特殊浮点值。
但注意:
- JSON 要求键名必须是双引号,
ast.literal_eval允许单引号 -
json.loads不接受 Python 特有语法,比如True、False、None—— 必须写成true、false、null - 如果字符串混用单双引号或含注释,两者都会失败,得先清洗
典型错误:json.loads("{'a': 1}") → JSONDecodeError: Expecting property name enclosed in double quotes
别忽略编码和空格问题,它们常导致 literal_eval 失败
ast.literal_eval 对空白字符敏感,尤其是开头/结尾不可见字符(BOM、零宽空格、换行符)。用户从表单或 Excel 复制的字符串经常带这些。
容易踩的坑:
- 字符串开头有
\ufeff(UTF-8 BOM)→ 直接抛ValueError - 末尾多了换行或空格,比如
"{'a': 1}\n "→ 同样失败 - 用
.strip()不够,得用.strip().replace('\u200b', '').replace('\u200c', '')清除零宽字符
稳妥做法:
s = s.strip()
if s.startswith('\ufeff'):
s = s[1:]
data = ast.literal_eval(s)
真实项目里,这类边缘情况比想象中多得多,尤其当数据来自前端粘贴、Excel 导出或低代码平台时。










