问题:
我想创建一个 lambda functions 的列表使用**kwargs
哪些在列表中迭代。
存在类似的问题( e.g. 、 e.g. ),但它们不考虑迭代 **kwargs
.
与之前一样,问题在于 kwargs
的值lambda 函数在列表中创建后会“延迟”求值,这意味着迭代期间分配的最后一个值将传递给所有 lambda 函数。
我已经验证这对于经典循环和推导式来说都是一个“问题”。
(2a)
不是,其值为 argset
从分配给所有 **kwargs
的理解的最后一次迭代开始。
(3a)
更糟糕的是,同时具有 argset
的值和i
从分配给 x
的最后一次迭代开始和**kwargs
.
MWE
代码
def strfun(x,**kwargs):
return 'x: {} | kwargs: {}'.format(x,kwargs)
argsets = [
{'foo': 'bar'},
{'baz': 'qux'},
]
# (1) expected behaviour:
print '(1) '+str([strfun(i,**argset) for i,argset in enumerate(argsets)])
# (2) unexpected behaviour:
funs = [lambda x: strfun(x,**argset) for argset in argsets]
print '(2) '+str([fun(i) for i,fun in enumerate(funs)])
# (3) unexpected behaviour:
funs = [lambda : strfun(i,**argset) for i,argset in enumerate(argsets)]
print '(3) '+str([fun() for fun in funs])
输出:
(1) ["x: 0 | kwargs: {'foo': 'bar'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2) ["x: 0 | kwargs: {'baz': 'qux'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(3) ["x: 1 | kwargs: {'baz': 'qux'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(1)
是“正确的”。
(2)
不是,最后一个值为 argsets
分配给**kwargs
适用于所有功能 ( {'baz': 'qux'}
)。
(3)
更糟糕的是,具有两者的最后一个值 i
和argsets
分配给x
和**kwargs
适用于所有函数( 1
和 {'baz': 'qux'}
)。
最佳答案
解决方案
解决方案1:functools.partial
按照 solution linked 的建议作者:@Blckknght 在上面的评论中,functools.partial
可能是执行此操作的最干净的方法(见下文)。
解决方案 2:嵌套 lambda
正如 @jfs 在 this answer 中所建议的那样,一种解决方法是定义 lambda 的外层,以在分配内部 lambda 期间强制评估迭代对象的当前值,并使用 map
滚动外部 lambda,创建所需的列表。
非常少的代码:
改变
[lambda x: fun(x,**kwargs) for kwargs in kwargset]
至 (1)
[partial(fun, **kwargs) for kwargs in kwargset]
或 (2)
map(lambda kwargs: (lambda x: fun(x,**kwargs)), kwargset)
完整 MWE
代码
from functools import partial
def strfun(x,**kwargs):
return 'x: {} | kwargs: {}'.format(x,kwargs)
argsets = [
{'foo': 'bar'},
{'baz': 'qux'},
]
# (1) always expected behaviour:
print '(1) '+str([strfun(i,**argset) for i,argset in enumerate(argsets)])
# (2)
# unexpected behaviour:
funs = [lambda x: strfun(x,**argset) for argset in argsets]
print '(2-x) '+str([fun(i) for i,fun in enumerate(funs)])
# expected behaviour
funs = map(lambda argset: (lambda x: strfun(x,**argset)), argsets)
print '(2-1) '+str([fun(i) for i,fun in enumerate(funs)])
# expected behaviour
funs = [partial(strfun, **argset) for argset in argsets]
print '(2-2) '+str([fun(i) for i,fun in enumerate(funs)])
# (3)
# unexpected behaviour:
funs = [lambda : strfun(i,**argset) for i,argset in enumerate(argsets)]
print '(3-x) '+str([fun() for fun in funs])
# expected behaviour
funs = map(lambda (i,argset): (lambda : strfun(i,**argset)), enumerate(argsets))
print '(2-1) '+str([fun() for fun in funs])
# expected behaviour
funs = [partial(strfun, i, **argset) for i,argset in enumerate(argsets)]
print '(2-2) '+str([fun() for fun in funs])
输出:
(1) ["x: 0 | kwargs: {'foo': 'bar'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2-x) ["x: 0 | kwargs: {'baz': 'qux'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2-1) ["x: 0 | kwargs: {'foo': 'bar'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2-2) ["x: 0 | kwargs: {'foo': 'bar'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(3-x) ["x: 1 | kwargs: {'baz': 'qux'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2-1) ["x: 0 | kwargs: {'foo': 'bar'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2-2) ["x: 0 | kwargs: {'foo': 'bar'}", "x: 1 | kwargs: {'baz': 'qux'}"]
(2-1),(2-2),(3-1),(3-2)
说明可能的解决方法。
关于python - ** lambda 函数列表理解中的 kwargs,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51637323/