将数学用户输入的语句作为Python 3中的代码执行

时间:2014-04-13 18:53:06

标签: python-3.x

如何允许用户输入诸如“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)

非常赞赏!

1 个答案:

答案 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"

可以轻松扩展到包含其他功能。