众所周知,使用eval()存在潜在的安全风险,因此提倡使用ast.literal_eval(node_or_string)

然而,在python 2.7中,运行此示例时返回ValueError: malformed string:

>>> ast.literal_eval("4 + 9")

而在python 3.3中,该示例的工作原理与预期一致:

>>> ast.literal_eval('4+9')
13

为什么它运行在Python3而不是Python2上?我如何在python 2.7中修复它而不使用高风险的eval()函数?

推荐答案

这在Python2上不起作用的原因在于它实现了literal_eval.当右操作数是复数时,原始实现仅对加法和减法执行数字求值.这在句法上对于复数表示为文字是必要的.

这是Python 3中的was changed,因此它支持任何类型的有效数字表达式位于加法和减法的任一侧.然而,literal_eval的使用仍然局限于加法和减法.

这主要是因为literal_eval应该是一个将单个constant文本(表示为字符串)转换为Python对象的函数.有点像简单内置类型的向后repr.不包括实际的表达式求值,而这一点在Python3中也适用,这只是它的实现带来的一个很好的副作用.

为了计算实际表达式,而不必使用eval(我们不想使用eval),我们可以编写自己的表达式计算算法,该算法在AST上运行.这非常简单,尤其是对于简单的数字算术运算(例如构建自己的计算器等).我们只需将字符串解析为AST,然后通过查看不同的 node 类型并应用正确的操作来判断生成的树.

比如:

import ast, operator

binOps = {
    ast.Add: operator.add,
    ast.Sub: operator.sub,
    ast.Mult: operator.mul,
    ast.Div: operator.div,
    ast.Mod: operator.mod
}

def arithmeticEval (s):
    node = ast.parse(s, mode='eval')

    def _eval(node):
        if isinstance(node, ast.Expression):
            return _eval(node.body)
        elif isinstance(node, ast.Str):
            return node.s
        elif isinstance(node, ast.Num):
            return node.n
        elif isinstance(node, ast.BinOp):
            return binOps[type(node.op)](_eval(node.left), _eval(node.right))
        else:
            raise Exception('Unsupported type {}'.format(node))

    return _eval(node.body)

正如您所看到的,这个实现非常简单.当然,它还不支持更复杂的东西,比如指数运算和一些一元 node ,但添加它们并不太困难.而且效果很好:

>>> arithmeticEval('4+2')
6
>>> arithmeticEval('4*1+2*6/3')
8

以后甚至可以引入更复杂的东西(例如,sin()之类的函数调用).

Python-3.x相关问答推荐

Paramiko SFTPClient get()和put()函数的通过/失败结果?

为什么我的Selenium脚本在密码元素上失败?

visual studio代码窗口中未激活虚拟环境11

使用Python抓取sofascore以获取有关球队阵容和投票的信息

当我在正则表达式末尾使用斜杠时,为什么会得到不同的结果?

调用 Clear 时 Airflow 会加载新代码吗

如何确保 GCP Document AI 模型输出与输入文件同名的 JSON?

如果集合大于 len(x),则 pandas 在重复的行中拆分集合列

如何使用复选按钮更改 Pyplot 轴的属性?

列出相同索引的Pandas

Snakemake 'run' 指令不产生错误信息

ValueError:FixedLocator 位置的数量 (5),通常来自对 set_ticks 的调用,与刻度标签的数量 (12) 不匹配

pip install dryscrape 失败并显示错误:[Errno 2] 没有这样的文件或目录:'src/webkit_server'?

如何调试垂死的 Jupyter Python3 内核?

如何使用 python 库连接到 poloniex.com websocket api

在 WSL (Ubuntu) 中为 python3 安装 venv

计数大于Pandas groupby 中的值的项目

新项目:Python 2 还是 Python 3?

finally 总是在 try 块返回之前运行,那么为什么 finally 块中的更新不会影响 try 块返回的变量的值呢?

有没有一种标准方法来确保 python 脚本将由 python2 而不是 python3 解释?