从yaml脚本

时间:2016-03-09 02:53:07

标签: python python-2.7 recursion nested

我有一个用于指定函数的yaml脚本。 yaml文件解析为我想用于构造此yaml文件中描述的函数的字典(实际上是嵌套字典)。这是一个yaml条目的例子:

Resistance:
   arguments:
      voltage: "V"
      current: "A"
   parameters:
      a: -1.23
      b: 0.772
   format: "{a}*voltage+{b}*current+f(voltage)"
   subfunctions:
      f:
         arguments:
            voltage: "V"             
         parameters:
            a: -6.32          
         format: "exp({a}*voltage)"

现在,需要做的是解析这个文件,然后构建名称空间,这样最后,我可以绑定一个名为" Resistance"的变量。反映上述函数的闭包或lambda(嵌套" f"子函数)。

我的策略是“自下而上”#34;使用递归算法。这是我的代码:

def evaluateSimpleFunction(entry):
    functionString = entry['format']    
    functionArgs = []
    Params = []

    if "arguments" in entry and entry["arguments"] != None:
        functionArgs = entry['arguments'].keys()
    if "parameters" in entry and entry["parameters"] != None:
        Params = entry['parameters']

    formatString = ""
    for param in Params:
        formatString += str(param)+"="+str(Params[param])+","
    functionString = eval("functionString.format("+formatString+")")

    lambdaString = ""
    for arg in functionArgs:
        lambdaString += str(arg)+","

    return eval("lambda " + lambdaString + ":" + functionString)

def recursiveLoader(entry):
    if "subfunctions" in entry:
        subfunctions = entry['subfunctions']
        bindingString = ""
        for subFunc in subfunctions:
            bindingString +=str(subFunc)+"=[];"
            exec(bindingString)
        for subFunc in subfunctions:
            exec(str(subFunc)+"= recursiveLoader(subfunctions[subFunc])")      
        return lambda : evaluateSimpleFunction(entry)            
    else:
        return lambda : evaluateSimpleFunction(entry)


import yaml,os, math
os.chdir(r"C:\Users\212544808\Desktop\PySim\xferdb")
keyFields = ["Resistance","OCV"]
containerKeys = ["_internalResistance","_OCV"]
functionContainer = {}

with open("LGJP1.yml",'r') as modelFile:
    parsedModelFile = yaml.load(modelFile)

#for funcKey,containerKey in zip(keyFields,containerKeys):  
entry = parsedModelFile["capacityDegrade"]
g = recursiveLoader(entry)

现在,我发现错误,因为我使用的是带有嵌套函数的非限定exec。

但是,我不想求助于全局变量,因为我会将此过程用于多个函数,因此会覆盖我使用的任何全局变量。

我希望有关如何从外部配置文件(如yaml文件)算法构建嵌套函数的建议 - exec似乎不是一种方法。

BTW:我使用的是Python 2.7

UPPDATE

另一个更强大的选项可能是使用全局类实例为每个函数创建命名空间。例如:

class Namespace(): pass

namespace_1 = Namespace()
#assume that the function "exponent" has arguments X, Y and body "Q(X*Y)", 
#where "Q" has body "x**2+3*y"
exec("namespace_1.exponent = lambda X,Y: Q(X*Y)")
exec("namespace_1.Q = lambda x,y: x**2+3*y")

这种方法的好处是我可以循环遍历类的成员以获得特定的函数来创建单个源代码字符串,我可以将其传递给" eval"获得最终的功能。

我正在做所有这些因为我没有找到使用eval和exec创建嵌套闭包的可靠方法。

1 个答案:

答案 0 :(得分:0)

这是我使用您输入的简化示例。我已经硬编码了,但您可以使用解析器轻松构建类似的模块文件:

def makeModule(**kwargs):
    print repr(kwargs)

    module_filename = 'generated_module.py'
    with open(module_filename, 'w') as module_file:
        module_file.write('''\
from math import *

def func(voltage, current):
    def f(voltage):
        return exp({a1} * voltage)

    return {a0}*voltage+{b}*current+f(voltage)
'''.format(**kwargs))

    module_name = module_filename.replace('.py', '')
    module = __import__(module_name)
    return module.func

def main():
    func = makeModule(a0=-1.23, b=0.772, a1=-6.32)
    print 'Result:', func(2, 3)

if __name__ == '__main__':
    main()

它的工作原理是生成一个名为 generated_module.py 的文件,然后使用内置函数__import__将其作为存储在变量module中的模块导入。与任何其他模块一样,您可以访问其中定义的名称,即func