如何允许用户输入诸如“math.sin(x)** 2”之类的语句并在python代码中计算答案。
在告诉我答案时,请解释为什么exec()compile()都没有产生所需的结果。
import math
def getValue(function, x):
function = "val = " + function
#compile(function, '', 'exec')
exec(function)
print(val)
function = input("Enter a function f(x):\n")
getValue(function, 10)
非常赞赏!
答案 0 :(得分:4)
要回答您的问题,请使用eval:
>>> eval('math.sin(1)**2')
0.7080734182735712
exec正在运行,但您没有检索结果。注意:
>>> val
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'val' is not defined
>>> exec('val=math.sin(1)**2')
>>> val
0.7080734182735712
因此,使用eval
代替exec
就像这样:
def getValue(function, x):
function = "{}({})".format(function, x)
print(function)
val=eval(function)
print(val)
这就是说 - 执行任意用户代码被视为极端安全风险。
如果您正在构建一个计算器,一种更安全的方法,您可以考虑使用SymPy或使用PyParsing(在SymPy中使用)等构建您自己的解析器
示例PyParsing计算器:
import sys
import operator
from pyparsing import nums, oneOf, Word, Literal, Suppress
from pyparsing import ParseException, Forward, Group
op_map = { '*' : operator.mul,\
'+' : operator.add,\
'/' : operator.div,\
'-' : operator.sub}
exp = Forward()
number = Word(nums).setParseAction(lambda s, l, t: int(t[0]))
lparen = Literal('(').suppress()
rparen = Literal(')').suppress()
op = oneOf('+ - * /').setResultsName('op').setParseAction(lambda s, l, t: op_map[t[0]])
exp << Group(lparen + op + (number | exp) + (number | exp) + rparen)
def processArg(arg):
if isinstance(arg, int):
return arg
else:
return processList(arg)
def processList(lst):
args = [processArg(x) for x in lst[1:]]
return lst.op(args[0], args[1])
def handleLine(line):
result = exp.parseString(line)
return processList(result[0])
while True:
try:
print handleLine(raw_input('> '))
except ParseException, e:
print >>sys.stderr,\
"Syntax error at position %d: %s" % (e.col, e.line)
except ZeroDivisionError:
print >>sys.stderr,\
"Division by zero error"
可以轻松扩展到包含其他功能。