在Python中,是否有更好的方法将函数列表应用于字典



有没有更好的方法将函数列表迭代地应用于字典?这是我想做的一个例子。 但这使用递归。

def func1(h: dict):
h['foo']=10
return(h)
def func2(h: dict):
h['bar']=100
return(h)
def func3(h: dict):
h['baz']=h['foo']+h['bar']
return(h)
func3(func2(func1({'firstElement':'good'})))

产生预期输出:

{'bar': 100, 'baz': 110, 'firstElement': 'good', 'foo': 10}

我想将函数作为数组提供并产生相同的输出。 这是我尝试和有效的:

def recApply(flist, h=None):
"""
Helper Apply the list of functions iteratively over the dictionary passed
:obj: function list each will be applied to the dictionary sequentially.
"""
#if no dictionary passed, then set the dictionary.
if(h == None):
h = {}
#iteratively call functions with dictionary as a passed parameter and returning a derived dictionary
for f in flist:
h = f(h)
return(h)
flist = [func1,func2,func3]
recApply(flist,{'firstElement':'good'})

这将产生所需的输出:

{'bar': 100, 'baz': 110, 'firstElement': 'good', 'foo': 10}

有没有一种方法可以做到这一点,它更具可读性,删除 recApply 函数并希望最大限度地减少字典副本?

您不需要返回字典并重新分配引用 - 可变类型通过引用传递,因此:

def func1(h):
h['foo'] = 10
def func2(h):
h['bar'] = 100
def func3(h):
h['baz'] = h['foo'] + h['bar']
start_dict = {'firstElement': 'good'}
for f in (func1, func2, func3):
f(start_dict)
print(start_dict)
# {'firstElement': 'good', 'baz': 110, 'bar': 100, 'foo': 10}

会完全没问题。

reduce(或 Python 3 中的functools.reduce)可用于将函数列表组合成单个函数。这需要您定义一个组合函数:

def compose(f, g):
def _(x):
return f(g(x))
return _

和一个恒等函数:

def identity(x):
return x

使用这些函数,您可以创建一个函数g,该函数将每个函数应用于初始输入。

g = reduce(compose, [func3, func2, func1], identity)
assert (g({'firstElement': 'good'}) ==
{'firstElement': 'good', 'foo': 10, 'bar': 100, 'baz': 110})

请注意,这是有效的,因为func1func2func3与纯函数非常相似,因此您可以使用函数幺半群。松散地说,它只是意味着函数组合是结合的(compose(f, compose(g, h))compose(compose(f, g), h)相同),并且恒等函数在组合下是中性的(compose(identity, f)compose(f, identity)都与f本身相同)。

你的三个函数并不是真正的纯函数;它们更像是带有副作用的恒等函数。但是,您可以将它们视为纯函数,因为您使用它们就好像它们被定义为

例如
def func1(h):
h1 = {}
h1.update(h)
h1['foo'] = 10
return h1

读者练习:确定我对reduce的调用是否真正定义了g(x) = func3(func2(func1(x)))g(x) = func1(func2(func3(x))

你也可以使用reduce(或functools.reduce在Python 3中)和起始字典作为initializer参数:

>>> from functools import reduce  # Python 3
>>> reduce(lambda (x, f): f(x), (func1, func2, func3), {'firstElement':'good'})
{'bar': 100, 'baz': 110, 'firstElement': 'good', 'foo': 10}

这会将函数一个接一个地应用于初始值设定项或前一个函数的结果。

您还可以将其与functools.partial结合使用,以创建一个链式函数,然后可以将其应用于不同的输入字典:

>>> from functools import partial
>>> chain = partial(reduce, lambda (x, f): f(x), (func1, func2, func3))
>>> chain({'firstElement':'good'})
{'bar': 100, 'baz': 110, 'firstElement': 'good', 'foo': 10}

你可以进一步概括这一点,使其成为partial函数的partial......

>>> chainer = partial(partial, reduce, lambda (x, f): f(x))
>>> chain = chainer((func1, func2, func3))
>>> chain({'firstElement':'good'})
{'bar': 100, 'baz': 110, 'firstElement': 'good', 'foo': 10}

相关内容

  • 没有找到相关文章

最新更新