如何让Python中eval()和exec()多行代码按先进先出顺序执行?
问题:multiline_eval函数执行顺序不符合预期
我参考了Stack Overflow上的一个问题,使用了其中的multiline_eval函数,代码如下:
def multiline_eval(expr, context={}): """Evaluate several lines of input, returning the result of the last line""" tree = ast.parse(expr) eval_exprs = [] exec_exprs = [] for module in tree.body: if isinstance(module, ast.Expr): eval_exprs.append(module.value) else: exec_exprs.append(module) exec_expr = ast.Module(exec_exprs, type_ignores=[]) exec(compile(exec_expr, 'file', 'exec'), context) results = [] for eval_expr in eval_exprs: results.append(eval(compile(ast.Expression((eval_expr)), 'file', 'eval'), context)) return '\n'.join([str(r) for r in results])
调用该函数执行以下代码时:
multiline_eval(''' print("Hello World1") for a in range(5): print(a) print("Hello World2") ''')
实际输出顺序为:
0 1 2 3 4 Hello World1 Hello World2
但期望的输出顺序是:
Hello World1 0 1 2 3 4 Hello World2
尝试修改代码未成功,请求指导如何调整代码实现预期输出顺序。
解决方案
问题出在原函数把ast.Expr类型的语句(比如直接的print()调用,属于表达式语句)和其他执行语句分开处理——先执行所有非表达式的exec语句,再单独处理表达式语句,直接打乱了代码原本的执行顺序。
要修复这个问题,核心是保留代码原本的执行顺序,不要拆分表达式和其他语句,按原顺序逐个处理每一条语句:
修改后的代码如下:
import ast def multiline_eval(expr, context=None): """按顺序执行多行输入,返回所有表达式语句的结果拼接""" if context is None: context = {} tree = ast.parse(expr) results = [] for stmt in tree.body: if isinstance(stmt, ast.Expr): # 处理表达式语句,执行并收集结果 result = eval(compile(ast.Expression(stmt.value), 'file', 'eval'), context) if result is not None: results.append(str(result)) else: # 处理执行语句,直接执行 exec(compile(ast.Module([stmt], type_ignores=[]), 'file', 'exec'), context) return '\n'.join(results)
关键调整说明:
- 移除原函数中拆分
exec_exprs和eval_exprs的逻辑,改为遍历每一条语句按原顺序处理 - 对每条语句判断类型后分别处理:
- 若为
ast.Expr(如print()调用这类表达式语句),用eval执行并收集结果 - 其他语句(如
for循环)直接用exec执行
- 若为
- 修复了原代码中
context默认参数的可变陷阱(用None作为默认值,函数内初始化空字典)
测试修改后的函数,执行原调用代码,即可得到预期的输出顺序:
Hello World1 0 1 2 3 4 Hello World2
内容的提问来源于stack exchange,提问作者Hunt3r
相关产品推荐
相关产品推荐

