使用pyparsing进行部分求值
我需要将一个使用OpenDocument公式语法的公式,解析成Python能理解的语法,但不需要立即计算变量的值。然后,我希望能够多次计算这个公式,每次用不同的变量值。
公式可能是用户输入的,所以使用pyparsing可以让我有效处理公式语法,并清理用户输入。网上有很多关于pyparsing的好例子,但所有的数学例子似乎都假设会立即在当前范围内计算所有内容。
为了让你更明白,我正在研究一个工业经济模型(生命周期评估,简称LCA),这些公式代表了不同过程之间的材料或能量交换量。这个量可能会根据多个参数变化,比如地理位置。公式和变量的引用链存储在一个有向无环图中,这样公式就能简单地被计算。公式以字符串的形式存储在数据库中。
我有几个问题:
- 有没有办法解析一个公式,使得解析后的结果也能以字符串的形式存储在数据库中(可以用来计算,或者其他形式)?
- 有没有其他方法可以实现这个目标?理想的解决方案是解析/写入一次,然后多次读取。例如,部分解析公式,然后使用ast模块,虽然我不知道这如何与数据库存储结合起来。
- 有没有类似的项目或库的例子可以参考?我不是程序员,只是一个学生,正在努力完成我的论文,同时在空闲时间制作一个开源的LCA软件模型。
- 这个方法会不会太慢?我希望能够进行大量的蒙特卡洛模拟,每次模拟可能涉及数万次公式计算(数据库很大)。
1 个回答
1) 是的,你可以把解析表达式的结果保存起来,然后存入数据库。这样你就可以直接取出这些结果,而不需要再次解析原始的表达式。
2) 你可以用一些简单的方法来实现这个,比如使用内置的 compile 和 eval 函数,下面是一个互动示例:
>>> y = compile("m*x+b","","eval")
>>> m = 100
>>> x = 5
>>> b = 1
>>> eval(y)
501
当然,这种方法有安全隐患,因为不可信或恶意的字符串可能会包含有害的系统调用。但如果这是你的论文,且完全在你的控制范围内,那就别做傻事。
3) 你可以在 pyparsing 的维基页面找到一个在线示例,展示如何把表达式解析成一个“可计算”的数据结构。特别推荐查看 simpleBool.py 和 evalArith.py。如果你有兴趣,可以订购 2008 年 5 月的 Python 杂志,里面有我写的文章“用 Pyparsing 编写简单的解释器/编译器”,详细描述了使用的方法,还有关于如何保存和恢复解析结果的说明。
4) 解析的过程会比较慢,所以你做得对,应该把这些结果保存成某种中间形式,方便重复计算。eval 的部分应该会比较快。第二个慢的部分是从数据库中获取这些保存的结构。在你的 MC 运行中,我建议你封装一个函数,这个函数接收表达式的选择参数,从数据库中获取数据,然后恢复并返回可计算的表达式。等这个功能正常工作后,可以使用一个缓存装饰器来存储这些查询结果,这样每个表达式只需要获取和恢复一次。
祝你的论文顺利!