【问题标题】:Python function from mathematical expression string来自数学表达式字符串的 Python 函数
【发布时间】:2020-09-08 21:18:47
【问题描述】:

有没有办法从一个字符串创建一个 python 函数?例如,我将以下表达式作为字符串:

dSdt = "-1* beta * s * i"

我找到了一种标记它的方法:

>>> import re
>>> re.findall(r"(\b\w*[\.]?\w+\b|[\(\)\+\*\-\/])", dSdt)
['-', '1', '*', 'beta', '*', 's', '*', 'i']

现在我想(不知何故 - 这是我不知道的部分)将其转换为具有相同行为的东西:

def dSdt(beta, s, i):
    return -1*beta*s*i

我考虑过类似eval(dSdt) 的东西,但我希望它更通用(必须提前知道参数betasi 存在)。


一些关闭请求已链接到this question,用于评估字符串中的数学表达式。这与这个问题不太一样,因为我正在寻找从该字符串定义一个函数。

【问题讨论】:

标签: python string function


【解决方案1】:

一种方法,使用 exec 从字符串中定义一个新函数

 expr = "-1* beta * s * i" 
 name = "dSdt" 
 params = ["beta","s","i"]  # Figure out how to build this array from expression
 param_str = ",".join(params) 
 exec (f"def {name}({param_str}): return {expr}")  

 dSdt(1,2,3)                                                                                                                                                            

 Out[]: -6

如果您不关心定义可重用函数,也可以将 eval 与全局对象参数一起使用。

 expr = "-1* beta * s * i" 
 param= {"beta":1, "s":2, "i":3}  # Find way to build this.
 eval(expr,param)


 Out[]: -6

【讨论】:

    【解决方案2】:

    这正是编译器或解释器所做的:从一种语言语法翻译成另一种语言语法。这里的主要问题是您希望何时能够执行结果函数?将函数写入文件以供其他程序稍后使用是否足够?或者您是否需要解析器以某种方式立即使用它?对于这两种情况,我都会编写一个解析器,从标记创建一个抽象语法树。这意味着您将需要制作一个更复杂的标记器,将每个标记标记为“运算符”、“数字”或“变量”。通常这是通过为每种类型的令牌编写一个正则表达式来完成的。

    然后您可以构建一个解析器,它一次使用每个标记,并构建一个表示表达式的抽象语法树。网上有很多材料解释了如何做到这一点,所以我建议用谷歌搜索一下。您可能还想寻找有助于解决此问题的库。

    最后,您可以遍历 AST 并将相应的 Python 语法写入文件,或者使用一些变量值的输入来评估表达式。

    【讨论】:

      【解决方案3】:

      您说的是您无法事先知道参数 - 这就是 *args 和 **kwargs 非常有用的地方!

      我喜欢你的这个想法,而且你制作的标记化功能效果很好。

      我为您制作了一个非常通用的函数,只要您在“忽略”列表中添加要使用的运算符和函数,它就可以处理任何表达式。然后,您只需按照它们在表达式中出现的顺序添加变量值。

      import re
      from math import sqrt
      
      ignore = ["+", "-", "*", "/", "(", ")", "sqrt"]
      
      def tokenize(expression):
          return re.findall(r"(\b\w*[\.]?\w+\b|[\(\)\+\*\-\/])", expression)
      
      def calculate(expression, *args):
          seenArgs = {}
          newTokens = []
          tokens = tokenize(expression)
          for token in tokens:
              try:
                  float(token)
              except ValueError:
                  tokenIsFloat = False
              else:
                  tokenIsFloat = True
      
              if token in ignore or tokenIsFloat:
                  newTokens.append(token)
              else:
                  if token not in seenArgs:
                      seenArgs[token] = str(args[len(seenArgs)])
                  newTokens.append(seenArgs[token])
          return eval("".join(newTokens))
      
      print(calculate("-1* beta * s * i", 1, 2, 3))
      print(calculate("5.5 * x * x", 3))
      print(calculate("sqrt(x) * y", 9, 2))
      

      结果:

      -6
      49.5
      6.0
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-09
        • 1970-01-01
        • 2012-05-29
        • 2015-12-03
        相关资源
        最近更新 更多