我可以通过exec()的名称空间传递参数集吗?

时间:2013-02-01 20:57:05

标签: python exec

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

1 个答案:

答案 0 :(得分:0)

传递给globals语句的localsexec仅影响exec正在执行的直接代码对象;它们不会影响代码对象调用的任何函数。 rptParam看到的全局变量仍然是模块全局变量,因此它模块中的v等打印值。

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

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

...

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