我正在尝试创建一个参数扫描模式,使用 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() 甚至是用于此目的的适当技术吗?