**在lambda函数的列表理解中比较困难

时间:2018-08-01 15:37:54

标签: python lambda list-comprehension kwargs

问题:

我想使用**kwargs创建一个lambda functions的列表,并在列表中进行迭代。

存在类似的问题(e.g.e.g.),但他们不考虑在**kwargs上进行迭代。

和以前一样,问题在于在列表中创建之后,lambda函数中kwargs的值被“懒惰地”求值,这意味着在迭代过程中分配的最后一个值将传递给所有lambda函数。 我已经证明这是经典循环和理解的“问题”。

(2a)并非如此,其值argset来自于对所有**kwargs的理解的最后一次迭代。 (3a)更糟,将上次迭代中的argseti的值都分配给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的{​​{1}}和argsets的最后一个值都分配给x**kwargs1)。

1 个答案:

答案 0 :(得分:1)

解决方案

解决方案1:{'baz': 'qux'}

正如@Blckknght的solution linked在上面的评论中所建议的那样,functools.partial可能是最干净的方法(见下文)。

解决方案2:嵌套functools.partial

正如@jfs在this answer中所建议的,一种解决方法是定义lambda的外层,以在分配内部lambda期间强制评估迭代对象的当前值,并使用lambda,创建所需的列表。

非常简单的代码:

更改

map

至(1)

[lambda x: fun(x,**kwargs) for kwargs in kwargset]

或(2)

[partial(fun, **kwargs) for kwargs in kwargset]

完整MWE

代码

map(lambda kwargs: (lambda x: fun(x,**kwargs)), kwargset)

输出:

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'}"] 说明了可能的解决方法。