在Python3中安全解析用户定义的方程式,无需eval



我的代码中有许多变量,如STA、INT、AGI和dmg_take,并且希望通过用户定义的方程来计算dmg_taked。作为概念的证明,我使用了eval,其工作原理如下。

不安全.py

dmg_min   = eval(self.rules.all_rules['dmg_min'])
dmg_max   = eval(self.rules.all_rules['dmg_max'])

包含方程式的外部规则文件看起来像

战斗规则

dmg_min = 2
dmg_max = round(((STR * 1.5) + (AGI * 1.02) + (INT * 1.3)) / 6 )

规则可以是数字,也可以是包含程序中使用的任意数量变量的公式——有什么更好的方法呢?

我还没有找到一种完全安全的方法来做到这一点,所以制定了以下内容。

  1. 用户定义的方程式可以由python代码库的用户完成(基本上,他们可以在控制代码时做他们想做的事情)

  2. 对于外部用户,所有方程参数都被拆分为变量,并以数字形式读取,因此不需要评估。

对规则文件的修改

dmg_INT_mult = 0.9
dmg_AGI_mult = 1.2
dmg_STR_mult = 1.2
dmg_INT_add = -.5
dmg_AGI_add = 0
dmg_STR_add = 0
dmg_overall_mult = 0.1667
dmg_overall_add = 0

这些参数用于在battle.py程序中建立方程

#   dmg_max = round(
#                    ((STR + dmg_STR_add) * dmg_STR_mult) 
#                  + ((AGI + dmg_AGI_add) * dmg_AGI_mult) 
#                  + ((INT + dmg_INT_add) * dmg_INT_mult)
#                  ) * dmg_overall_mult 
#             + dmg_overall_add

新代码

calc_agi = round((AGI + float(self.rules.all_rules['dmg_AGI_add'])) * float(self.rules.all_rules['dmg_AGI_mult']))
calc_int = round((INT + float(self.rules.all_rules['dmg_INT_add'])) * float(self.rules.all_rules['dmg_INT_mult']))
calc_str = round((STR + float(self.rules.all_rules['dmg_STR_add'])) * float(self.rules.all_rules['dmg_STR_mult'])) 
dmg_max = round((calc_agi + calc_int + calc_str) * float(self.rules.all_rules['dmg_overall_mult']) + float(self.rules.all_rules['dmg_overall_add']))

这是安全的,因为读取的所有参数都转换为浮点,因此任何字符串都会导致异常,并允许最终用户建立相当复杂的方程。

相关内容

最新更新