Why is Python's eval() rejecting this multiline string, and how can I fix it?

删除回忆录丶 提交于 2019-12-18 05:44:22

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!