问题
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,
回答1:
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
回答2:
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) + "")''','abc','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", 'abc', 'single') # works with simple expressions too
In [160]: eval cc
--------> eval(cc)
Out[160]: 4
>>> help(compile)
compile(...)
compile(source, filename, mode[, flags[, dont_inherit]]) -> code object
Compile the source string (a Python module, statement or expression)
into a code object that can be executed by the exec statement or eval().
The filename will be used for run-time error messages.
The mode must be 'exec' to compile a module, 'single' to compile a
single (interactive) statement, or 'eval' to compile an expression.
The flags argument, if present, controls which future statements influence
the compilation of the code.
The dont_inherit argument, if non-zero, stops the compilation inheriting
the effects of any future statements in effect in the code calling
compile; if absent or zero these statements do influence the compilation,
in addition to any features explicitly specified.
回答3:
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
回答4:
(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.
Security warning
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.
来源:https://stackoverflow.com/questions/12698028/why-is-pythons-eval-rejecting-this-multiline-string-and-how-can-i-fix-it