我可以在保留 lambda 表达式的同时删除双重评估吗
Posted
技术标签:
【中文标题】我可以在保留 lambda 表达式的同时删除双重评估吗【英文标题】:Can I remove double evaluation whilst keeping lambda expression 【发布时间】:2019-08-12 01:27:12 【问题描述】:def bar(x):
# some expensive calculation
<snip>
foo = lambda(x): bar(x) if bar(x) > 10 else 0
但是在这里我计算了 foo 两次。有没有办法仍然把它写成一个衬里但避免双重评估。我试过了
foo = lambda(x): v if (v = bar(x)) > 10 else 0
但这不起作用。
【问题讨论】:
您可以将 foo(x) 存储在一个变量 tmp 中并在您的代码中使用它。 【参考方案1】:我尝试过制作一些函数装饰器/包装器...
def funcdec(func):
def inner(x):
if func(x) > 10:
return func(x)
else:
return 0
然后
@funcdec
def bar(x):
return x * 2
那我试试....:
foo = lambda x: bar(x)
给我结果:
foo(2)
返回 0 和
foo(10)
返回 20
【讨论】:
【参考方案2】:还不如定义另一个函数:
def bar(x):
# some expensive calculation
<snip>
def bar_threshold(x,t):
y = bar(x)
return y if y>t else 0
foo = lambda x: bar_threshold(x,10)
(或重新定义栏,如果您发现自己仅在阈值上使用它)
【讨论】:
【参考方案3】:预评估:
foo = lambda(x): x if x > 10 else 0
result = foo(bar(x))
在这里你可以看到你的代码有什么相似之处:
lambda (x): foo(x) if foo(x) > 10 else 0 == (lambda(x): x if x > 10 else 0)(foo(x))
除非您创建某种可变状态对象或其他一些奇怪的技巧,否则您所寻求的是不可能的。
@Alakazam 的答案既棘手又聪明,使用它需要您自担风险。最好使用迭代器和next
来避免额外的中间列表:
lambda x: next(res if res > 10 else 0 for res in (bar(x), ))
这里有live example
【讨论】:
【参考方案4】:是的,您可以避免在 lambda 中进行双重评估。但它真的很难看,你应该避免它。下面是它的外观:
foo = lambda x: next(b if b > 10 else 0 for b in [bar(x)])
这是否易于阅读和理解?不,绝对不是。我不打算解释它;看看你能不能弄清楚。这显然不是一个好的解决方案,那么您应该怎么做呢?您应该使用真正的函数而不是 lambda。
def foo(x):
b = bar(x)
return b if b > 10 else 0
这更容易阅读,而且明显更好。
【讨论】:
【参考方案5】:您可能只想在您的函数执行时间很长时才这样做,否则您不应该介意运行它两次。您不能使用列表推导。
foo = lambda x: [res if res>10 else 0 for res in [bar(x)]][0]
【讨论】:
我认为这个更好:lambda x: next(res if res > 10 else 0 for res in (bar(x), ))
,原因是您避免了中间内存分配
@Netwave 我不认为中间 malloc 是相关的,即使它取决于函数,你也不会节省很多内存。以上是关于我可以在保留 lambda 表达式的同时删除双重评估吗的主要内容,如果未能解决你的问题,请参考以下文章
使用 lambda 表达式时删除附加的事件处理程序 [重复]