1

因此,我正在编写一个程序,该程序需要将表达式作为用户输入,并在值随程序内时间变化时评估该表达式。会有很多这样的表达方式。会有一个“播放”功能让时间前进,所以我想保持快速(ish)这通常意味着“找到别人写的东西”,但我当然不反对自己写东西。

我期待这样的事情作为输入

input> sin(currentTime()*360) - (plant.height*5 + root.depth**2)

我已经研究过标记化和构建 ast 等,但我显然错过了最后一步,在该步骤中,我得到了一个可以随着多个输入的变化而反复评估的函数。

在正确的大方向上的任何推动都将是最有帮助的。谢谢!

4

2 回答 2

0

我已经做了类似的事情来对事件应用任意过滤规则,以查看是否需要采取行动作为响应。事件和相关上下文将作为参数传递给从包装在 lambda 中的任意表达式编译的函数。

# API consists of the variables:
# - plant
# - root
# - currentTime
# math.* and random.* are imported

exprs = """\
sin(currentTime()*360) - (plant.height*5 + root.depth**2)
cos(currentTime()*180) - (plant.height*3 + root.depth**(1.5 + random()*0.5))""".splitlines()

# function to 'compile' expression into an executable function
def makeFunction(expr):
    # define args that are supported in the expression
    api = "plant,root"
    return eval("lambda %s : %s" % (api, expr))

# compile given expressions into functions
fns = [makeFunction(e) for e in exprs]

这是一个模拟包装器,用于展示它在您的大型程序中的外观:

from math import *
from random import *

# mock up simple classes and vars to simulate larger program
def simpleClass(clsname, **kwargs):
    classDefn = "class %s:\n  %s=%s" % (clsname, ','.join(kwargs.keys()), 
                                        ','.join(map(str,kwargs.values())))
    print classDefn
    exec(classDefn, globals())

def mockProgramVars():
    # define some simple classes for API variables
    simpleClass("Plant", height=0, stem=0)
    simpleClass("Root", depth=0, thickness=0, radius=0)
    return Plant(), Root()

plant, root = mockProgramVars()


# loop through time, evaluating functions as plant and root grow
for T in range(0,10):
    # note, local vars become implicit part of API for functions
    def currentTime():
        return T

    # define explicit args
    args = (plant, root)

    # invoke compiled functions
    print T, ":", 
    for i,fn in enumerate(fns, start=1):
        print fn(*args),
    print

    # have plant grow a bit before next time
    plant.height += 0.1
    root.depth += 0.2

印刷:

class Plant:
  stem,height=0,0
class Root:
  depth,radius,thickness=0,0,0
0 : 0.0 1.0
1 : 0.418915723414 -0.948727984564
2 : -1.70407169644 -1.12048780375
3 : -2.5102191366 -0.418297794419
4 : -1.72700555043 -2.69830945686
5 : -3.36779764724 -2.4337532978
6 : -5.42800370907 -2.38542932493
7 : -5.03162665152 -4.90632786047
8 : -5.81504769652 -4.46741225807
9 : -8.59104601264 -5.02132453755

当然,所有关于使用 eval 的标准警告都适用。

于 2013-09-05T08:08:46.390 回答
0

如果您不介意输入格式是 Python,那么有一个ast模块可以为您进行解析。literal_eval 帮助程序安全地执行 AST 或源代码字符串。如果有帮助,这个问题有一些关于使用函数操作范围的内容。

于 2013-09-05T01:39:20.273 回答