Python如何将含无引号键的键值对字符串转换为字典
问题场景
Python开发过程中,需要将包含无引号非字符串键的键值对字符串转换为字典类型,待处理的示例代码如下:
employee='{"Priority":{0:"High"},"Age":{range(0,5):"high"}}'
实现方法
首先明确两个常规方案的局限性:
json.loads()完全无法处理这类字符串:JSON规范强制要求对象键必须是双引号包裹的字符串,且不支持range这类Python特有表达式,直接调用会报解析错误。ast.literal_eval()也不能直接用:这个安全解析方法仅支持原生字面量类型(数字、字符串、列表、字典、元组、布尔值、None),range()属于函数调用,不在它的允许范围内,直接调用会抛ValueError。
根据你的数据源可信程度,可以选下面两种方案实现:
方案1:可信数据源下的轻量实现
如果待转换的字符串是内部生成、完全可控没有注入风险的,可以用eval搭配受限命名空间快速转换,屏蔽掉危险内置方法,仅保留需要的range:
employee_str = '{"Priority":{0:"High"},"Age":{range(0,5):"high"}}' # 限制全局命名空间,切断危险内置函数的访问路径,仅暴露range safe_ns = {"__builtins__": {"range": range}} employee = eval(employee_str, safe_ns)
执行后得到的就是标准字典:
print(employee) # 输出: {'Priority': {0: 'High'}, 'Age': {range(0, 5): 'high'}} print(employee["Priority"][0]) # 输出: High print(employee["Age"][range(0,5)]) # 输出: high
注意:这个方法禁止用来处理用户提交、外部传入的不可信字符串,避免代码注入风险。
方案2:不可信数据源下的安全实现
如果要处理来源不确定的字符串,可以基于AST做白名单解析,只允许你需要的语法结构通过,从根源上堵死注入风险,示例代码如下:
import ast def safe_parse_dict(s: str) -> dict: def _traverse_node(node): if isinstance(node, ast.Expression): return _traverse_node(node.body) # 解析字典结构 if isinstance(node, ast.Dict): return {_traverse_node(k): _traverse_node(v) for k, v in zip(node.keys, node.values)} # 解析常量(字符串、数字、None等) if isinstance(node, ast.Constant): return node.value # 仅允许range函数调用,参数必须为合法字面量 if isinstance(node, ast.Call): if not (isinstance(node.func, ast.Name) and node.func.id == "range"): raise ValueError("解析错误:存在不允许的函数调用") args = [_traverse_node(arg) for arg in node.args] return range(*args) # 兼容Python3.8以下版本的字面量节点 if isinstance(node, ast.Num): return node.n if isinstance(node, ast.Str): return node.s raise ValueError(f"解析错误:存在不支持的语法结构 {type(node)}") ast_tree = ast.parse(s, mode="eval") return _traverse_node(ast_tree) # 调用示例 employee_str = '{"Priority":{0:"High"},"Age":{range(0,5):"high"}}' employee = safe_parse_dict(employee_str)
这个解析器遇到任何不在白名单里的语法(比如导入模块、执行系统命令的表达式)都会直接抛错,安全性可以满足生产环境处理外部输入的要求。
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

