如何创建部分依赖于外部参数的函数数组? (蟒蛇)

时间:2015-03-16 02:54:01

标签: python-3.x

我有兴趣创建一个由许多小函数“g”组成的函数列表/数组“G”。这基本上应该对应于一系列功能“及时发展”。

每个“g”接受两个变量并返回这些变量的乘积,并在同一时间步长索引外部全局变量。

假设obs_mat(T x 1)是预定义的全局数组,t对应于时间步

G = []

for t in range(T):
    # tried declaring obs here too.               
    def g(current_state, observation_noise):
        obs = obs_mat[t] 
        return current_state * observation_noise * obs 

G.append(g) 

不幸的是,当我测试结果函数时,它们似乎没有发现obs时变常数的差异,即(G[0](100,100)G[5](100,100)相同)。我尝试了obs的范围但没有太多运气。有人能帮助指导我朝正确的方向发展吗?

3 个答案:

答案 0 :(得分:3)

这是一个常见的"陷阱"在内部函数中引用外部作用域的变量。运行内部函数时查找外部变量,而不是在定义内部函数时查找(因此函数的所有版本都会看到变量的最后一个值)。要使每个函数看到不同的值,您需要确保它们在不同的命名空间中查找,或者您需要将该值绑定到内部函数的默认参数。

这是一种使用额外命名空间的方法:

def make_func(x):
    def func(a, b):
        return a*b*x
    return func

list_of_funcs = [make_func(i) for i in range(10)]

每个内部函数func都可以访问封闭式x函数中的make_func参数。由于它们都是通过对make_func的单独调用创建的,因此它们每个都会看到具有不同x值的单独命名空间。

这是另一种使用默认参数的方法(使用lambda表达式创建的函数):

list_of_funcs = [lambda a, b, x=i: a*b*x for i in range(10)]

在此版本中,列表推导中的i变量绑定到lambda表达式中x参数的默认值。这种绑定意味着函数不会关心i稍后更改的值。这个解决方案的缺点是,任何意外调用其中一个函数而不是两个参数的代码都可以正常工作(可能有奇怪的结果)。

答案 1 :(得分:2)

您遇到的问题是范围界定问题。在实际调用函数之前,函数体不会被评估,因此您在那里使用的函数将在评估时使用其范围内变量的当前值(这意味着它们具有相同的{如果在for循环结束后全部调用它们,则为{1}}

为了查看您想要的值,您需要立即调用该函数并保存结果。

我不确定你为什么要使用一系列功能。也许您在整个时间序列中尝试做的是map a partial function,如下所示?

t

这里发生的是from functools import partial def g(current_state, observation_noise, t): obs = obs_mat[t] return current_state * observation_noise * obs g_maker = partial(g, current, observation) results = list(map(g_maker, range(T))) 创建一个部分应用的函数,它只是在等待它的最终值被评估。该最终值是动态的(但在此示例中前两个是固定的),因此在一系列值上映射部分应用的函数可以获得每个值的答案。

老实说,这是一个猜测,因为很难看出你还试图用这些数据做什么,而且你很难看到你用这个数据试图实现的目标。函数(当然还有其他方法)。

答案 2 :(得分:2)

问题(假设您的G.append调用错误缩进)只是在循环t返回的迭代器时突变名称range(T)。由于您创建的每个函数g都返回相同的名称t,因此它们最终会返回相同的值T - 1。解决方法是取消引用名称(最简单的方法是将t作为g参数列表中参数的默认值发送到函数中:< / p>

G = []

for t in range(T):
    def g(current_state, observation_noise, t_kw=t):
        obs = obs_mat[t_kw] 
        return current_state * observation_noise * obs

    G.append(g)

这是有效的,因为它创建了另一个名称,该名称指向 t在循环的迭代期间引用(您仍然可以使用t而不是{{1它仍然可以工作,因为t_kw g 绑定到t f 绑定的值 - 值永远不会改变,但是t f 在下一次迭代时被绑定到另一个值,而t g 仍然指向&#34;原始&#34;值。