简体   繁体   English

在python中有更好的方法将功能列表应用于字典

[英]in python is there a better way to apply a list of functions to a dictionary

Is there a better way to iteratively apply a list of functions to a dictionary? 有没有更好的方法可以迭代地将功能列表应用于字典? Here is an example of what I want to do. 这是我想做的一个例子。 But this uses recursion. 但这使用了递归。

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'})))

Produces expected output: 产生预期的输出:

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

I want to provide the functions as a array and produce the same output. 我想以数组形式提供函数并产生相同的输出。 Here is what I have tried and works: 这是我尝试和工作的内容:

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'})

This produces the desired output: 这将产生所需的输出:

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

Is there a way to do this that is more readable, removes the recApply function and hopefully minimizes dictionary copies? 有没有一种方法可以使此方法更具可读性,可以删除recApply函数并希望最大程度地减少字典副本?

You don't need to return your dictionaries and re-assign references - mutable types are passed by reference so: 您不需要返回字典并重新分配引用-可变类型通过引用传递,因此:

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}

would to perfectly fine. 会完美的。

reduce (or functools.reduce in Python 3) can be used to compose a list of functions into a single function. reduce (或Python 3中的functools.reduce )可用于将函数列表组合为一个函数。 This requires you to define a composition function: 这要求您定义一个合成函数:

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

and an identity function: 和一个身份函数:

def identity(x):
    return x

Using these, you can create a function g that applies each function in order to an initial input. 使用这些,您可以创建将每个功能应用到初始输入的功能g

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

Note this works because func1 , func2 and func3 are similar enough to pure functions that you can make use of the function monoid . 请注意,这是func1 ,因为func1func2func3与纯函数足够相似,您可以使用函数monoid Loosely speaking, it just means that function composition is associative ( compose(f, compose(g, h)) is the same as compose(compose(f, g), h) ) and that the identity function is neutral under composition ( compose(identity, f) and compose(f, identity) are both the same as f itself). 松散地说,这仅表示函数组合是关联的( compose(f, compose(g, h))compose(compose(f, g), h) ),并且恒等函数在组合下是中性的( compose(identity, f)compose(f, identity)f本身相同。

Your three functions aren't really pure functions; 您的三个函数并不是真正的纯函数。 they are more like identity functions with side effects. 它们更像具有副作用的身份功能。 However, you can treat them as pure functions because you are using them as if they were defined as, for example, 但是,您可以将它们视为纯函数,因为您使用它们时就好像它们被定义为例如,

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

Exercise for the reader: determine if my call to reduce actually defines g(x) = func3(func2(func1(x))) or g(x) = func1(func2(func3(x)) . 读者的练习:确定我的reduce调用是否实际上定义了g(x) = func3(func2(func1(x)))g(x) = func1(func2(func3(x))

You could also use reduce (or functools.reduce in Python 3) with the starting dictionary as the initializer parameter: 您还可以将reduce (或Python 3中的functools.reduce )与起始字典一起用作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}

This will apply the functions one after the other to the initializer or the result of the previous function. 这会将函数一个接一个地应用于初始化器或上一个函数的结果。

You could also combine this with functools.partial to create a chained function that can then be applied to different input dictionaries: 您也可以将其与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}

And you could generalize that further, making it a partial of a partial function... 你可能会进一步笼统地说,使其成为partial A的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}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM