How to get results out of a Python exec()/eval() call?

送分小仙女□ 提交于 2019-12-02 05:19:31

The exec function will modify the global parameter (dict) passed to it. So you can use the code below

code_str="""import math
Result1 = math.sqrt(width**2 + height**2)
"""
context = {
    'width' : 30,
    'height' : 10
}

exec(code_str, context)

print (context['Result1']) # 31.6

Every variable code_str created will end up with a key:value pair in the context dictionary. So the dict is the "object" like you mentioned in JavaScript.

Edit1:

If you only need the result of the last line in code_str and try to prevent something like Result1=..., try the below code

code_str="""import math
math.sqrt(width**2 + height**2)
"""

context = { 'width' : 30, 'height' : 10 }

lines = [l for l in code_str.split('\n') if l.strip()]
lines[-1] = '__myresult__='+lines[-1] 

exec('\n'.join(lines), context)
print (context['__myresult__'])

This approach is not as robust as the former one, but should work for most case. If you need to manipulate the code in a sophisticated way, please take a look at the Abstract Syntax Trees

Since this whole exec() / eval() thing in Python is a bit weird ... I have chose to re-design the whole thing based on a proposal in the comments to my question (thanks @jonrsharpe).

Now, the whole study specification is a .py module that the user can edit. From there, the configuration setup is directly written to a central object of the whole package. On tool runs, the configuration module is imported using the code below

import imp

# import the configuration as a module
(path, name) = os.path.split(filename)
(name, _) = os.path.splitext(name)
(file, filename, data) = imp.find_module(name, [path])

try:
    module = imp.load_module(name, file, filename, data)
except ImportError as e:
    print(e)
    sys.exit(1)
finally:
    file.close()

I came across similar needs, and finally figured out a approach by playing with ast:

import ast
code = """
def tf(n):
  return n*n
r=tf(3)
{"vvv": tf(5)}
"""
ast_ = ast.parse(code, '<code>', 'exec')
final_expr = None
for field_ in ast.iter_fields(ast_):
    if 'body' != field_[0]: continue
    if len(field_[1]) > 0 and isinstance(field_[1][-1], ast.Expr):
        final_expr = ast.Expression()
        final_expr.body = field_[1].pop().value
ld = {}
rv = None
exec(compile(ast_, '<code>', 'exec'), None, ld)
if final_expr:
    rv = eval(compile(final_expr, '<code>', 'eval'), None, ld)
print('got locals: {}'.format(ld))
print('got return: {}'.format(rv))

It'll eval instead of exec the last clause if it's an expression, or have all execed and return None.

Output:

got locals: {'tf': <function tf at 0x10103a268>, 'r': 9}
got return: {'vvv': 25}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!