2013-02-01 55 views
0

我想创建一个参数扫描模式,使用python的exec()函数并通过一个名称空间传递给它一个特定的参数集。我的应用程序是一个带有一堆参数的scipy.integrate.odeint()模型,但是我尝试创建一个SSCCE测试用一个简单的参数报告函数替换它。同样,我没有包含整套参数和范围,因为这些示例使这些变得明显。我可以通过exec()的名字空间传递一个参数吗?

def rptParam(): 
    print 'rptParam: v=%e b0=%e drme=%e de=%e TGrate=%f IPer=%d' % (v,b0,drme,de,TGrate,IPer) 

def tstIterExec(argList, argRange, seed): 

    seedTup = tuple([seed[k] for k in argList]) 
    print 'tstIterExec: seed', seedTup 
    seed['rptParam'] = rptParam 
    tstCode = compile("rptParam()", '<string>','exec') 

    for param,v in seed.items(): 
     if param not in argList: 
      print 'tstIterExec: skipping param', param 
      continue 

     print 'tstIterExec: varying', param 
     ai = argList.index(param) 
     spos = argRange[ai].index(v) 
     # higher values of param 
     for vi in range(spos+1,len(argRange[ai])): 
      currContext = seed.copy() 
      currContext[param] = argRange[ai][vi]    # perturb just this value of seed 
      seedTup = tuple([currContext[k] for k in argList]) # a hashable version of the seed 
      print 'tstIterExec: perturb', param, seedTup 
      exec tstCode in globals(), currContext 


tstArgList = ['v','b0'] 
tstArgRange = [v_Range, b0_Range] 

TstSeed = {'v':3e-2, 'b0':2e-11, 'drme':5e-2, 'de':0.8 ,'TGrate': 0.2, 'IPer':10} 
tstIterExec(tstArgList, tstArgRange, TstSeed) 

运行这段代码产生这样的输出:

tstIterExec: seed (0.03, 2e-11) 
tstIterExec: skipping param drme 
tstIterExec: skipping param TGrate 
tstIterExec: skipping param de 
tstIterExec: varying b0 
tstIterExec: perturb b0 (0.03, 4e-11) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: perturb b0 (0.03, 8e-11) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: perturb b0 (0.03, 1e-10) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: perturb b0 (0.03, 1e-09) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: varying v 
tstIterExec: perturb v (0.032, 2e-11) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: perturb v (0.048, 2e-11) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: perturb v (0.064, 2e-11) 
rptParam: v=3.200000e-02 b0=2.000000e-11 drme=5.000000e-02 de=8.500000e-01 TGrate=0.200000 IPer=10 
tstIterExec: skipping param rptParam 
tstIterExec: skipping param IPer 

显然,currContext是内tstIterExec(),但rptParam(改变)坚持使用全局绑定?我也尝试将currContext作为第一个全局名称空间发送;同样的行为。

我一定是误解python的命名空间/关闭概念? exec()甚至适用于此目的的技术?

回答

0

传递给exec语句的globalslocals只影响立即执行的代码对象exec;它们不会影响代码对象调用的任何函数。如rptParam所示的全局变量仍然是模块全局变量,因此它的模块中的打印值为v等。

至于我可以告诉最好的选择将只是接受参数作为参数:

def rptParam(v, ...): 
    ... 

... 

      print 'tstIterExec: perturb', param, seedTup 
      rptParam(**currContext) 
+0

感谢ecatmur,我同意作为传递明确的参数可能是一个变通。但实际上函数调用函数......最终调用scipy.integrate.odeint()函数。我认为闭包是处理这个问题的好方法,我认为exec命名空间能够做到这一点? – rikb

+0

@rikb'exec'不影响代码中其他位置定义的函数的关闭。您可以随时传递参数,只在需要时将其解包。 – ecatmur

+0

我一直希望得到来自其他Pythonics的第二意见;缺少Lisp特性让我感觉很老(:@ecatmur,即使我不喜欢它,我也很欣赏你的答案 – rikb

相关问题