如何在不修改self.data的情况下实现字典键的代数表达式求值?
解决eval修改原字典的问题
问题原因
当你将self.data直接作为eval()的globals参数传入时,Python会自动向这个字典中添加__builtins__键,这就是原字典被修改的根源。
方案1:用临时字典避免修改原数据
不需要深拷贝,只需构造一个包含self.data内容的新字典,传给eval()即可。原字典self.data不会被改动,因为eval()只会修改传入的临时字典。
代码实现:
import ast class A(): def __init__(self, data=None): self.data = {} if data is None else data def __getitem__(self, src:str): parsed_expr = ast.parse(src, mode='eval') compiled_expr = compile(parsed_expr, '', 'eval') # 构造临时全局字典,包含原数据和内置模块 temp_globals = {**self.data, '__builtins__': __builtins__} item = eval(compiled_expr, temp_globals) return item obj = A({'open':1,'close':1}) print(obj['close + open']) # 输出2 print(obj.data) # 输出{'open':1,'close':1},无__builtins__
方案2:限制内置函数提升安全性(可选)
如果担心表达式中调用危险内置函数,可以只提供运算所需的最小内置集合,进一步降低风险:
import ast import math class A(): def __init__(self, data=None): self.data = {} if data is None else data def __getitem__(self, src:str): parsed_expr = ast.parse(src, mode='eval') compiled_expr = compile(parsed_expr, '', 'eval') # 只提供必要的内置函数和数学工具 safe_globals = { **self.data, '__builtins__': { 'abs': abs, 'pow': pow, 'sum': sum, **math.__dict__ } } item = eval(compiled_expr, safe_globals) return item obj = A({'open':1,'close':1}) print(obj['(open+close)/2']) # 输出1.0 print(obj.data) # 原字典未被修改
内容的提问来源于stack exchange,提问作者apt45
相关产品推荐
相关产品推荐

