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

globalsステートメントにlocals渡されたとは、execによって実行されている直接のコード オブジェクトにのみ影響しexecます。コード オブジェクトが呼び出す関数には影響しません。で見られるグローバルrptParamはまだモジュールグローバルであるため、モジュールにある値vなどを出力しています。

私が知る限り、最善の策はパラメータを引数として受け入れることです:

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

...

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