假设我在字符串中有一些python代码
code = """
a = 42
a
"""
和我exec
那段代码:
result = exec(code)
然后result
始终为None
。是否有任何方法可以获得最后一个表达式的值?在这种情况下,那将是5
,因为a
是最后一个表达式。
编辑:这是我要问的功能的另一个例子。假设我们有python代码(存储在变量code
)
a = 100
sqrt(a)
那么如何执行代码以便给我结果10
- 即sqrt(a)
?
编辑编辑:另一个例子:我希望exec
的代码是
function_a()
function_b()
function_c()
我有什么方法可以定义某种magic_exec
函数,以便
magic_exec(code)
会为我提供function_c()
的价值吗?
答案 0 :(得分:3)
请求肯定是有效的,因为在创建基于Python的环境中我也需要这样的功能。我使用以下使用Python ast机制的代码解决了这个问题:
def my_exec(script, globals=None, locals=None):
'''Execute a script and return the value of the last expression'''
stmts = list(ast.iter_child_nodes(ast.parse(script)))
if not stmts:
return None
if isinstance(stmts[-1], ast.Expr):
# the last one is an expression and we will try to return the results
# so we first execute the previous statements
if len(stmts) > 1:
exec(compile(ast.Module(body=stmts[:-1]), filename="<ast>", mode="exec"), globals, locals)
# then we eval the last one
return eval(compile(ast.Expression(body=stmts[-1].value), filename="<ast>", mode="eval"), globals, locals)
else:
# otherwise we just execute the entire code
return exec(script, globals, locals)
代码应该是不言自明的,基本上是
答案 1 :(得分:0)
exec('a = 4')
print a % prints 4
>>> code = """
... a = 42
... b = 53"""
>>> exec(code)
>>> a
42
>>> b
53
或者,如果你说你不知道最后一件事是b,那么你可以这样:
code = """
a = 4
b = 12
abc_d=13
"""
t = re.findall(r'''.*?([A-Za-z0-9_]+)\s*?=.*?$''', code)
assert(len(t)==1)
print t[0] % prints 13
答案 2 :(得分:0)
这并不能获得最后一次评估的值,但会得到整个局部变量列表。
>>> loc = {}
>>> exec(code, {}, loc)
>>> loc
{'a': 42}
答案 3 :(得分:0)
说实话,我不能说我对此非常满意。感觉非常hacky,我还没有对它进行过多次测试。另一方面,我对它很满意。这很有意思。无论如何,希望这可以帮助你或至少接近你想要的。 locals()
给出了一个dict,因此输出列表顺序与第一个eval
失败的项的输入顺序不匹配。如果您不希望';'
作为分隔符,则可以将其更改为'\n'
。
import math
def magic_exec(_command):
_command = _command.split(';')
_result = None
_before = list(locals()) # Get list of current local variables
for _code in _command:
_code = _code.strip() # .strip() prevent IndentationError
try:
if eval(_code) != None: # For functions with no return
_result = eval(_code)
except (NameError, SyntaxError):
try:
_before = list(locals())
exec(_code)
except NameError as e: # For undefined variables in _command
print("An Error Occurred with line ' {0} ' as was skipped: {1}".format(_code, e))
del _code # delete temp var _code
# Get new list of locals that didn't exist at the start
_after = [val for val in list(locals()) if val not in _before]
if _after:
return eval(_after[0])
else:
return _result
#Dummy class and functions
class Class1(object):
def __init__(self, x):
self._x = x
def get_val(self):
return self._x
def __repr__(self):
return type(self).__name__
def func1(x):
return x + x
def func2(x):
print(x*x)
if __name__ == '__main__':
code = \
"""
a = 42; a; v; y = 2; b = func1(5); s = 'Hello'; func2(10); c = 25; l = []; l.append('Value');
t = math.sqrt(c); pass; 20*10; print('TEST'); math.sqrt(c); d = Class1('World'); d.get_val();
def func3(x): return x ** 2; s = func3(15)
"""
values = magic_exec(code)
print(values)
答案 4 :(得分:0)
我想补充一下user2283347的excellent answer,它仅适用于Python 3.7。在Python 3.8中,ast.Module.__init__
的签名已更改。现在,它需要第二个参数,在我们的例子中可以是一个空列表。
详细信息:{p中的ast.Module(body=stmts[:-1])
if len(stmts) > 1:
exec(compile(ast.Module(body=stmts[:-1]), filename="<ast>", mode="exec"), globals, locals)
必须更改为
ast.Module(stmts[:-1], [])
(如果您使用Python 3.8或更高版本)(请注意第二个参数[]
)。否则,将引发以下TypeError
:
TypeError: required field "type_ignores" missing from Module
很遗憾,此更改没有得到很好的记录。经过广泛的Google搜索之后,我找到了解决方案:"IPython broken on 3.8-dev"。