0

我正在尝试创建一个参数扫描模式,使用 python 的 exec() 函数并通过命名空间传递一个特定的参数集。我的应用程序是一个带有一堆参数的 scipy.integrate.odeint() 模型,但是我尝试创建一个SSCCE测试用一个简单的参数报告功能代替了它。同样,我没有包含完整的参数和范围,因为这些示例很明显。

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() 甚至是用于此目的的适当技术吗?

4

1 回答 1

0

传递给语句的globalsand只影响由;执行的直接代码对象。它们不会影响代码对象调用的任何函数。所看到的全局变量仍然是模块全局变量,因此它正在打印模块中的 etc. 值。localsexecexecrptParamv

据我所知,最好的选择就是接受参数作为参数:

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

...

            print 'tstIterExec: perturb', param, seedTup
            rptParam(**currContext)
于 2013-02-01T22:30:56.437 回答