猿问

计算字符串中的数学表达式

计算字符串中的数学表达式

stringExp = "2^4"intVal = int(stringExp)      # Expected value: 16

这将返回以下错误:

Traceback (most recent call last):  File "<stdin>", line 1, in <module>ValueError: invalid literal for int()with base 10: '2^4'

我知道eval是否有一种更好、更安全的方法来计算存储在字符串中的数学表达式?


有只小跳蛙
浏览 832回答 3
3回答

长风秋雁

eval是邪恶的eval("__import__('os').remove('important file')") # arbitrary commandseval("9**9**9**9**9**9**9**9", {'__builtins__': None}) # CPU, memory注意:即使您使用SET__builtins__到None仍然有可能通过内省来爆发:eval('(1).__class__.__bases__[0].__subclasses__()', {'__builtins__': None})使用astimport astimport operator as op# supported operatorsoperators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ast.USub: op.neg}def eval_expr(expr):&nbsp; &nbsp; """&nbsp; &nbsp; >>> eval_expr('2^6')&nbsp; &nbsp; 4&nbsp; &nbsp; >>> eval_expr('2**6')&nbsp; &nbsp; 64&nbsp; &nbsp; >>> eval_expr('1 + 2*3**(4^5) / (6 + -7)')&nbsp; &nbsp; -5.0&nbsp; &nbsp; """&nbsp; &nbsp; return eval_(ast.parse(expr, mode='eval').body)def eval_(node):&nbsp; &nbsp; if isinstance(node, ast.Num): # <number>&nbsp; &nbsp; &nbsp; &nbsp; return node.n&nbsp; &nbsp; elif isinstance(node, ast.BinOp): # <left> <operator> <right>&nbsp; &nbsp; &nbsp; &nbsp; return operators[type(node.op)](eval_(node.left), eval_(node.right))&nbsp; &nbsp; elif isinstance(node, ast.UnaryOp): # <operator> <operand> e.g., -1&nbsp; &nbsp; &nbsp; &nbsp; return operators[type(node.op)](eval_(node.operand))&nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; raise TypeError(node)您可以很容易地限制每个操作或任何中间结果的允许范围,例如限制输入参数a**b:def power(a, b):&nbsp; &nbsp; if any(abs(n) > 100 for n in [a, b]):&nbsp; &nbsp; &nbsp; &nbsp; raise ValueError((a,b))&nbsp; &nbsp; return op.pow(a, b)operators[ast.Pow] = power或者限制中间结果的大小:import functoolsdef limit(max_=None):&nbsp; &nbsp; """Return decorator that limits allowed returned values."""&nbsp; &nbsp; def decorator(func):&nbsp; &nbsp; &nbsp; &nbsp; @functools.wraps(func)&nbsp; &nbsp; &nbsp; &nbsp; def wrapper(*args, **kwargs):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ret = func(*args, **kwargs)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mag = abs(ret)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; except TypeError:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pass # not applicable&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if mag > max_:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raise ValueError(ret)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return ret&nbsp; &nbsp; &nbsp; &nbsp; return wrapper&nbsp; &nbsp; return decoratoreval_ = limit(max_=10**100)(eval_)例>>> evil = "__import__('os').remove('important file')">>> eval_expr(evil) #doctest:+IGNORE_EXCEPTION_DETAILTraceback (most recent call last):...TypeError:>>> eval_expr("9**9")387420489>>> eval_expr("9**9**9**9**9**9**9**9") #doctest:+IGNORE_EXCEPTION_DETAILTraceback (most recent call last):...ValueError:

慕无忌1623718

一些安全的替代方案eval()和sympy.sympify().evalf()*:阿斯瓦瓦numexpr*塞佩sympify也是不安全的,根据以下来自文档的警告。警告:请注意,此函数使用eval,因此不应该用于未经消毒的输入。
随时随地看视频慕课网APP

相关分类

Python
我要回答