Python一行调用函数列表

时间:2012-11-29 18:35:51

标签: python function events iteration

我有一些旧代码,我在Python中将函数列表存储为类属性。这些列表用作一种事件挂钩。

要使用适当的参数调用列表中的每个函数,我使用了单行,将maplambda表达式混合使用。我现在担心使用这样的lambda表达式会产生不必要的开销。我想推荐的方法是删除maplambda并使用标准for循环,为了便于阅读。

有没有更好的(更快阅读)单行代码呢?

例如:

class Foo:
    """Dummy class demonstrating event hook usage."""
    pre  = [] # list of functions to call before entering loop.
    mid  = [] # list of functions to call inside loop, with value
    post = [] # list of functions to call after loop.
    def __init__(self, verbose=False, send=True):
        """Attach functions when initialising class."""
        self._results = []
        if verbose:
            self.mid.append( self._print )
        self.mid.append( self._store )
        if send:
            self.post.append( self._send )

    def __call__(self, values):

        # call each function in self.pre (no functions there)
        map( lambda fn: fn(), self.pre )

        for val in values:
            # call each function in self.mid, with one passed argument
            map( lambda fn: fn(val), self.mid )

        # call each fn in self.post, with no arguments
        map( lambda fn: fn(), self.post )

    def _print(self, value):
        """Print argument, when verbose=True."""
        print value

    def _store(self, value):
        """Store results"""
        self._results.append(value)

    def _send(self):
        """Send results somewhere"""

# create instance of Foo
foo = Foo(verbose=True)

# equivalent to: foo.__call__( ... )
foo( [1, 2, 3, 4] )

有没有更好的方法来编写这些单线map来电?

3 个答案:

答案 0 :(得分:2)

推荐的方法肯定是使用for循环,但是,如果你坚持使用map,那么operator.methodcaller可能就是你所需要的:

>>> def foo(*args):
...    print 'foo',args
... 
>>> def bar(*args):
...    print 'bar',args
... 
>>> from operator import methodcaller
>>> 
>>> map(methodcaller('__call__',1,2,3),[foo,bar])
foo (1, 2, 3)
bar (1, 2, 3)
[None, None]

关于使用map的注意事项 - 如果将代码移植到python 3,那么它将无法工作,因为map变得懒惰。

你也可以非常简单地使用列表推导(也适用于python3):

[fn() for fn in self.pre]
[fn(val) for fn in self.mid]

答案 1 :(得分:1)

首先“我担心有不必要的开销”无法优化您的代码。使用分析器查找热点。

其次,您的代码可以使用注释来让读者知道发生了什么。

最后,除非另有证明,否则以下是完成任务的好方法:

for func in self.pre: func()
#apply every function in self.mid to every value in values
for func,val in itertools.product(self.mid, values):
    func(val)

如果要捕获值,可以使用列表推导;如果你想延迟评估,可以使用生成器表达式。

答案 2 :(得分:0)

>>> def chain(*fn):
>>>     return lambda *args, **kwargs: [_(*args, **kwargs) for _ in fn]
>>>
>>> def add(x, y):
>>>    return(x + y)
>>>
>>> def multiply(x, y):
>>>    return(x * y)
>>>
>>> chained = chain(add, multiply)
>>> chained(2, 6)

[8, 12]