2

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

为了使用适当的参数调用列表中的每个函数,我使用了单行代码,map并与lambda表达式混合。我现在担心使用lambda这样的表达式会产生不必要的开销。我想推荐的方法是同时删除mapandlambda并且只使用标准 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电话?

4

3 回答 3

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]

等等

于 2012-11-29T18:45:05.143 回答
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)

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

于 2012-11-29T18:48:50.123 回答
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]

于 2020-03-29T20:53:32.123 回答