Python:通过loads()加载JSON字符串时无法解析内嵌字典项
解决方案
方案1:用AST+受限命名空间安全求值
eval()的安全风险在于它会执行任意代码,而通过ast模块解析表达式并在受限命名空间中执行,可以避免这个问题——只传入你允许访问的变量,且禁用所有内置函数。
示例代码:
import ast # 你的目标字典 target_dict = {"product": "Laptop", "price": 999} # 从文本文件读取的参数引用字符串 param_ref = "target_dict['product']" # 将字符串解析为AST表达式树 expr_tree = ast.parse(param_ref, mode='eval') # 在受限环境中执行:仅传入允许的变量,禁用内置函数 result = eval( compile(expr_tree, filename='', mode='eval'), {"__builtins__": None}, # 禁用所有内置函数,防止恶意调用 {"target_dict": target_dict} # 只暴露需要访问的字典 ) print(result) # 输出: Laptop
这个方法允许支持Python风格的字典引用,但严格限制了可访问的变量范围,不会执行恶意代码。
方案2:自定义参数标记与解析规则
如果可以调整文本文件的参数格式,用自定义标记(比如{{dict.key}})来表示字典项,然后自己实现解析逻辑,完全避免代码执行风险。
示例实现:
import re def resolve_dict_refs(param_str, allowed_dicts): """解析带自定义标记的参数字符串,替换为字典实际值""" def replace_match(match): ref_expr = match.group(1) # 拆分引用路径,支持 dict['key'] 或 dict.key 格式 parts = ref_expr.split('.') current = allowed_dicts for part in parts: # 处理带引号的键(如 'product') if part.startswith(("'", '"')) and part.endswith(("'", '"')): key = part[1:-1] current = current[key] else: current = current[part] return str(current) # 匹配 {{dict_ref}} 格式的标记 return re.sub(r'\{\{([^}]+)\}\}', replace_match, param_str) # 使用示例 my_dict = {"product": "Laptop", "price": 999} text_param = "商品名称:{{my_dict['product']}},价格:{{my_dict.price}}" resolved_param = resolve_dict_refs(text_param, {"my_dict": my_dict}) print(resolved_param) # 输出: 商品名称:Laptop,价格:999
这个方案最可控,完全由你定义解析规则,不存在代码执行的安全隐患,适合对安全性要求高的场景。
方案3:改用支持引用的安全配置格式
如果文本文件可以改为更规范的配置格式(如YAML),可以利用格式本身的引用机制,配合安全加载器实现需求。
比如用YAML自定义标签实现字典键引用:
import yaml # 自定义YAML标签处理器,解析 !ref 标签 def ref_constructor(loader, node): ref_path = loader.construct_scalar(node) parts = ref_path.split('.') current = loader.construct_mapping(loader.nodes[0], deep=True) for part in parts: if part.startswith(("'", '"')) and part.endswith(("'", '"')): key = part[1:-1] current = current[key] else: current = current[part] return current yaml.add_constructor('!ref', ref_constructor) # 配置文件内容示例 config_content = """ my_dict: product: Laptop price: 999 function_params: name: !ref my_dict.product cost: !ref my_dict['price'] """ # 安全加载配置 config = yaml.safe_load(config_content) print(config['function_params']['name']) # 输出: Laptop
这个方案适合需要复杂配置的场景,依赖成熟的配置解析库,安全性更高。
内容的提问来源于stack exchange,提问作者theZeigs
相关产品推荐
相关产品推荐

