Reputation: 5993
I am attempting to eval the following tab-indented string:
'''for index in range(10):
os.system("echo " + str(index) + "")
'''
I get, "There was an error: invalid syntax , line 1"
What is it complaining about? Do I need to indent to match the eval() statement, or write it to a string file or temp file and execute that, or something else?
Thanks,
Upvotes: 29
Views: 30184
Reputation: 517
A better version.
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])
So you can run code in Qt.
Upvotes: 1
Reputation: 250951
To use such statements with eval
you should convert them to code object first, using compile:
In [149]: import os
In [150]: cc = compile('''for index in range(10):
os.system("echo " + str(index) + "")''','<string>','single')
In [154]: eval cc
--------> eval(cc)
0
Out[154]: 0
1
Out[154]: 0
2
Out[154]: 0
3
Out[154]: 0
4
In [159]: cc = compile("2+2", '<string>', 'single') # works with simple expressions too
In [160]: eval cc
--------> eval(cc)
Out[160]: 4
Upvotes: 18
Reputation: 1779
(See default security warning at end before you put code like this into production!)
The other answers do a good job of explaining the difference between exec
and eval
.
Nevertheless, I found myself wanting to take input like x=1; y=2; x+y
rather than force people to write:
def f():
x = 1
y = 2
return x + y
String manipulation of code to build this sort of function is a risky business.
I ended up using the following approach:
def multiline_eval(expr, context):
"Evaluate several lines of input, returning the result of the last line"
tree = ast.parse(expr)
eval_expr = ast.Expression(tree.body[-1].value)
exec_expr = ast.Module(tree.body[:-1])
exec(compile(exec_expr, 'file', 'exec'), context)
return eval(compile(eval_expr, 'file', 'eval'), context)
This parses python code; uses the ast library to rebuild an ast of everything apart from the last line; and the last line, execing the former and eval'ing the later.
This is the obligatory security warning that you have to attach to eval
.
Eval
'ing and exec
'ing code that is provided by a non-privileged user is of course insecure. In these cases you may prefer to use another approach, or consider ast.literal_eval. eval
and and exec
tend to be bad ideas unless you actually want to give your user the full expressive power of python.
Upvotes: 7
Reputation: 375485
We evaluate (eval
) expressions, and execute (exec
) statements.
See: Expression Versus Statement.
Expression: Something which evaluates to a value. Example: 1+2/x
Statement: A line of code which does something. Example: GOTO 100
Upvotes: 7
Reputation: 113978
eval
evaluates stuff like 5+3
exec
executes stuff like for ...
>>> eval("for x in range(3):print x")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1
for x in range(3):print x
^
SyntaxError: invalid syntax
>>> exec("for x in range(3):print x")
0
1
2
>>> eval('5+3')
8
Upvotes: 38