python - 压缩和应用函数列表和相应参数的 TypeError
问题描述
问题:
让f1
,f2
成为其他参数的两个函数x
和不同数量的其他参数;他们实际上做了什么是无关紧要的,但我将使用 delta 函数来说明:
def f1(x, p1, p2, v):
if x == p1:
return v
elif x == p2:
return v
else:
return 0
def f2(x, p1, v):
if x == p1:
return v
else:
return 0
我现在想构造一个函数,它返回一个函数列表,该列表是x
两个函数在各种组合中的总和:
import itertools
def choice_matrix(n):
return itertools.product(*[range(n)]*n)
def f(fn1, fn2, n):
aux1 = [[fn1 if ae == 0 else fn2 for ae in ar] for ar in choice_matrix(n)]
aux2 = [
lambda x, args: sum(
[fn(x, *arg) for fn, arg in zip(fns, args)]
) for fns in aux1
]
return aux2
wherechoice_matrix
只是一个函数,它返回n
位置的两个元素的各种组合:
>>> cm = list(choice_matrix(2))
>>> for i in range(len(cm)): print(cm)
(0, 0)
(0, 1)
(1, 0)
(1, 1)
通过从函数打印,我可以看到它aux1
按预期工作,并且确实返回了一个函数矩阵:
[<function f1 at 0x7efbdec08730>, <function f1 at 0x7efbdec08730>]
[<function f1 at 0x7efbdec08730>, <function f2 at 0x7efbdec087b8>]
[<function f2 at 0x7efbdec087b8>, <function f1 at 0x7efbdec08730>]
[<function f2 at 0x7efbdec087b8>, <function f2 at 0x7efbdec087b8>]
作为测试,我现在尝试f1 + f2
使用一些参数打印返回列表 (so) 的第二个函数:
vs = [(1., 2., 3.), (4., 5.)]
test0 = f(f1, f2, 2)
test = test0[1]
print(test(1., vs))
f1
有 4 个参数,f2
有 3 个参数,一切似乎都很好,按照任何逻辑,这段代码都应该 return 3.0
。然而,我得到的是一个TypeError
; 该函数采用的位置参数少于给出的参数:
Traceback (most recent call last):
File "test.py", line 323, in <module>
print(test(1., vs))
File "test.py", line 283, in <lambda>
arg in zip(aux1[i], args)])
File "test.py", line 283, in <listcomp>
arg in zip(aux1[i], args)])
TypeError: f2() takes 3 positional arguments but 4 were given
到目前为止我尝试了什么:
- 类似的列表理解:
def f(fn1, fn2, n):
aux1 = [[fn1 if ae == 0 else fn2 for ae in ar] for ar in choice_matrix(n)]
for i in range(len(aux1)): print(aux1[i])
aux2 = [
lambda x, args: list(
map(
lambda fn, arg: fn(x, *arg), fns, args
)
) for fns in aux1
]
return aux2
这给出了相同的结果。
- 对其基本组件操作的完整解构,
aux2
以查看出现了什么问题:
def f(fn1, fn2, n):
aux1 = [[fn1 if ae == 0 else fn2 for ae in ar] for ar in choice_matrix(n)]
aux2 = {}
for i in range(len(aux1)):
print(i)
print(aux1[i])
print(set(zip(aux1[i], vs)))
aux2[i] = lambda x, args: sum([fn(x, *arg) for fn,
arg in zip(aux1[i], args)])
if i == 1: fun = aux2[i]; print(fun(1., vs))
print('')
return aux2
令人惊讶的是,似乎没有任何问题。这是所有这些print
s的输出i = 1
:
1
[<function f1 at 0x7efbdef23730>, <function f2 at 0x7efbdef237b8>]
{(<function f2 at 0x7efbdef237b8>, (4.0, 5.0)), (<function f1 at 0x7efbdef23730>, (1.0, 2.0, 3.0))}
3.0
因此函数及其参数排列为正确压缩,正确压缩,正确应用并返回预期值,但我仍然得到相同的精确值,TypeError
因此一旦参数传递到函数外部,压缩就会中断.
- 避免压缩的伪功能重写:
def f(fn1, fn2, n):
aux1 = [[fn1 if ae == 0 else fn2 for ae in ar] for ar in choice_matrix(n)]
def a(fns, x, args):
if len(fns) == 0 or len(args) == 0:
return []
else:
fhead, *ftail = fns
ahead, *atail = args
return [fhead(x, *ahead)] + a(ftail, x, atail)
for i in range(len(aux1)):
print('i =', i)
print(aux1[i])
if i == 1: print(a(aux1[i], 1., vs)); print(sum(a(aux1[i], 1., vs)))
print('')
aux2 = [lambda x, args: a(fs, x, args) for fs in aux1]
return aux2
内部打印输出给出了预期的结果:
i = 1
[<function f1 at 0x7efbdec19730>, <function f2 at 0x7efbdec197b8>]
[3.0, 0]
3.0
然而TypeError
仍然存在。
我在这里束手无策。我做错了什么,如何使此代码正常运行?有没有更健壮和/或优雅的方式来做到这一点?
解决方案
这是一个常见的错误。Python 使用词法作用域闭包,因此在嵌套列表推导中,您的 lambdafn
从外部列表推导中捕获为局部变量:
aux2 = [lambda x, args: sum(
[fn(x, *arg) for fn, arg in zip(fns, args)]
) for fns in aux1]
这个变量fns
。
但是在lambda
评估时,您是否已经完成了迭代aux1
,所以fns
指的是所有 lambda所产生的最后一个值。aux1
您必须注意在循环中创建闭包。修复很简单,创建另一个封闭范围:
def f(fn1, fn2, n):
aux1 = [[fn1 if ae == 0 else fn2 for ae in ar] for ar in choice_matrix(n)]
aux2 = [(lambda _fns: lambda x, args: sum(
[fn(x, *arg) for fn, arg in zip(_fns, args)]
))(fns)
for fns in aux1]
return aux2
我劝你不要这么简洁,python 风格对于任何习惯使用 Haskell 的人来说都是相对冗长的。另外,请注意, to 的参数sum
可以是生成器表达式,以免在将整个列表传递给sum
您需要的列表理解之前实现整个列表(它被急切地评估):
aux2 = [
(lambda _fns: lambda x, args:
sum( fn(x, *arg) for fn, arg in zip(_fns, args) )
)(fns)
for fns in aux1
]
推荐阅读
- unreal-engine4 - 如果不重新启动,虚幻引擎将无法启动到 Oculus Quest 2
- python - 一个类必须实现所有抽象方法吗?
- angular - Angular 10 表单动作没有变化
- apache-kafka - Quarkus Kafka - 批量/批量消息消费者
- python - 使用 lxml 和 xpath 的代码适用于单个 xml 文件,但在扩展到类似 xml 的集合时会失败
- python - 在 python 代码中找不到“名称未定义”的原因
- c - 为什么我在运行我的 c 程序后总是得到 0?请帮帮我
- python - 使用图像、Flask、Gcloud Storage、Openpyxl 流式传输 Excel 文件时出现问题,无法保存所有图像的文件
- ssh - 在“ddev auth ssh”上找不到目录
- php - 如何使用“href”清除 $_GET 变量?