我有一些旧代码,我在Python中将函数列表存储为类属性。这些列表用作一种事件挂钩。
要使用适当的参数调用列表中的每个函数,我使用了单行,将map
与lambda
表达式混合使用。我现在担心使用这样的lambda
表达式会产生不必要的开销。我想推荐的方法是删除map
和lambda
并使用标准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
来电?
答案 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]