我有兴趣创建一个由许多小函数“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
的范围但没有太多运气。有人能帮助指导我朝正确的方向发展吗?
答案 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;值。