我正在编写一个程序,其中方程式作为字符串输入,然后进行评估。到目前为止,我已经想出了这个:
test_24_string = str(input("Enter your answer: "))
test_24 = eval(test_24_string)
我需要这个等式的字符串版本和评估版本。但是,eval
是一个非常危险的功能。但是,使用int()
不起作用,因为它是一个等式。是否有Python函数将从字符串中计算数学表达式,就像输入数字一样?
答案 0 :(得分:5)
一种方法是使用numexpr。它主要是用于优化(和多线程)numpy操作的模块,但它也可以处理数学python表达式:
>>> import numexpr
>>> numexpr.evaluate('2 + 4.1 * 3')
array(14.299999999999999)
您可以在结果上调用.item
以获得类似python的类型:
>>> numexpr.evaluate('17 / 3').item()
5.666666666666667
这是第三方扩展模块,所以它可能在这里完全矫枉过正,但它比eval
更安全,并且支持许多功能(包括numpy
和math
操作)。如果还支持“变量替换”:
>>> b = 10
>>> numexpr.evaluate('exp(17) / b').item()
2415495.27535753
python标准库的一种方法是ast.literal_eval
,但非常有限。它适用于Python中最基本的数据类型和文字:
>>> import ast
>>> ast.literal_eval('1+2')
3
但失败的表达更为复杂,如:
>>> ast.literal_eval('import os')
SyntaxError: invalid syntax
>>> ast.literal_eval('exec(1+2)')
ValueError: malformed node or string: <_ast.Call object at 0x0000023BDEADB400>
不幸的是,+
和-
以外的任何运营商都是不可能的:
>>> ast.literal_eval('1.2 * 2.3')
ValueError: malformed node or string: <_ast.BinOp object at 0x0000023BDEF24B70>
我在这里复制了部分文档,其中包含支持的类型:
安全地评估表达式节点或包含Python文字或容器显示的字符串。提供的字符串或节点可能只包含以下Python文字结构:字符串,字节,数字,元组,列表,字符串,集合,布尔值和无。
答案 1 :(得分:2)
编写后缀表达式求值程序并不困难。下面是一个工作示例。 (还有available在github上。)
import operator
import math
_add, _sub, _mul = operator.add, operator.sub, operator.mul
_truediv, _pow, _sqrt = operator.truediv, operator.pow, math.sqrt
_sin, _cos, _tan, _radians = math.sin, math.cos, math.tan, math.radians
_asin, _acos, _atan = math.asin, math.acos, math.atan
_degrees, _log, _log10 = math.degrees, math.log, math.log10
_e, _pi = math.e, math.pi
_ops = {'+': (2, _add), '-': (2, _sub), '*': (2, _mul), '/': (2, _truediv),
'**': (2, _pow), 'sin': (1, _sin), 'cos': (1, _cos), 'tan': (1, _tan),
'asin': (1, _asin), 'acos': (1, _acos), 'atan': (1, _atan),
'sqrt': (1, _sqrt), 'rad': (1, _radians), 'deg': (1, _degrees),
'ln': (1, _log), 'log': (1, _log10)}
_okeys = tuple(_ops.keys())
_consts = {'e': _e, 'pi': _pi}
_ckeys = tuple(_consts.keys())
def postfix(expression):
"""
Evaluate a postfix expression.
Arguments:
expression: The expression to evaluate. Should be a string or a
sequence of strings. In a string numbers and operators
should be separated by whitespace
Returns:
The result of the expression.
"""
if isinstance(expression, str):
expression = expression.split()
stack = []
for val in expression:
if val in _okeys:
n, op = _ops[val]
if n > len(stack):
raise ValueError('not enough data on the stack')
args = stack[-n:]
stack[-n:] = [op(*args)]
elif val in _ckeys:
stack.append(_consts[val])
else:
stack.append(float(val))
return stack[-1]
用法:
In [2]: from postfix import postfix
In [3]: postfix('1 2 + 7 /')
Out[3]: 0.42857142857142855
In [4]: 3/7
Out[4]: 0.42857142857142855
答案 2 :(得分:0)
我遇到了同样的问题,并解决了这个问题:
def safe_math_eval(string):
allowed_chars = "0123456789+-*(). /"
for char in string:
if char not in allowed_chars:
raise Exception("Unsafe eval")
return eval(string)
仍然有一个我看不到的安全问题。 如果有安全问题,请告诉我。