我需要执行一行由用户输入的python代码。
如果它是一个语句我想执行它,但如果它是一个表达式,我希望返回结果并用它做一些奇特的东西。
问题是python有两个不同的功能,即exec
和eval
。
目前我只是尝试评估用户输入的字符串。 如果这引发了一个SyntaxError,这可能表明该字符串是一个语句,所以我尝试执行它。
try:
result = eval(command, scope)
except SyntaxError:
# Probably command is a statement, not an expression
try:
exec(command, scope)
except Exception as e:
return command + ' : ' + str(e)
except Exception as e:
return command + ' : ' + str(e)
else:
pass # Some fancy stuff
这感觉相当hacky。是否有更整洁,更蟒蛇的方式来做到这一点?
答案 0 :(得分:4)
虽然我认为你现有的代码可能是合理的Pythonic(根据它的原则#34;更容易请求宽恕而不是许可")我怀疑最好的替代方法是使用{{ 3}}模块检查字符串中的代码:
tree = ast.parse(some_input_string)
if len(tree.body) == 1 and isinstance(tree.body[0], ast.Expr):
result = eval(some_input_string, scope)
else:
exec(some_input_string, scope)
result = None
请注意,一些常见的陈述实际上是"表达式陈述"。因此,像'do_stuff("args")'
这样的输入字符串将使用上面代码的eval
分支,而不是exec
分支。我不认为这会产生任何不良后果,但你永远不会知道。
还可以编译已解析的tree
,然后将结果传递到eval
或exec
来电。尽管如此,我发现它非常繁琐(你需要将ast.Expr
的{{1}}属性包装在顶部分支的value
中,所以我选择了更简单的方法(阅读和理解)只是传入字符串并让Python再次解析它的替代方法。
答案 1 :(得分:0)
你可以重构一下try-except。您的示例中没有真实的上下文,但假设您希望能够执行a=1
然后评估a
并获得1
,那么您可以执行类似的操作。 ..
from code import InteractiveConsole
interpreter = InteractiveConsole()
def run(code):
try: return eval(code.strip(), interpreter.locals)
except: pass
try: interpreter.runcode(code)
except Exception as error: return error
这也适用于多行代码。
在不了解您的目标的情况下,很难说如何做到最好,但是您的原则很好,只需要整理。这个类似的answer再次包含了同一个try-except逻辑的最小版本,重点是更忠实地模仿解释器。
答案 2 :(得分:0)
你错过了一个,实际上有三个函数与执行代码有关,而你错过的函数是compile()
。
compile()
需要三个必需的参数,要编译的代码,正在编译的模块的名称,它将出现在源自该代码的回溯中,以及"模式"。 mode参数应该是" exec"之一,用于编译整个模块," eval"用于编译简单表达式,以及"单个",它应该是一行交互式输入!
在所有三种情况下,您都将返回的code
对象传递给eval
,并带有所需的上下文:
>>> c = compile("if 1 < 2:\n print(3)", "<string>", "single")
>>> eval(c)
3
>>>