可以通过操作抽象语法树 (AST) 为 eval 表达式“分配”一个值。不需要直接修改评估字符串,如果新值的类型不是太复杂(例如数字或字符串),您可以将其硬编码到 AST 中:
- 将 eval 表达式编译为 AST。
- 将根节点处的 Load 表达式上下文替换为 Store。
- 在根节点使用 Assign 语句创建新的 AST。
- 将 target 设置为修改后的 eval AST 的表达式节点。
- 将 value 设置为 value。
- 将新的 AST 编译为字节码并执行。
示例:
import ast
import numpy as np
def eval_assign_num(expression, value, global_dict, local_dict):
expr_ast = ast.parse(expression, 'eval', 'eval')
expr_node = expr_ast.body
expr_node.ctx = ast.Store()
assign_ast = ast.Module(body=[
ast.Assign(
targets=[expr_node],
value=ast.Num(n=value)
)
])
ast.fix_missing_locations(assign_ast)
c = compile(assign_ast, 'assign', 'exec')
exec(c, global_dict, local_dict)
class TestClass:
arr = np.array([1, 2])
x = 6
testClass = TestClass()
arr = np.array([1, 2])
eval_assign_num('arr[0]', 10, globals(), locals())
eval_assign_num('testClass.arr[1]', 20, globals(), locals())
eval_assign_num('testClass.x', 30, globals(), locals())
eval_assign_num('newVarName', 40, globals(), locals())
print('arr', arr)
print('testClass.arr', testClass.arr)
print('testClass.x', testClass.x)
print('newVarName', newVarName)
输出:
arr [10 2]
testClass.arr [ 1 20]
testClass.x 30
newVarName 40