我可以在保留 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&gt;10 else 0 for res in [bar(x)]][0]

【讨论】:

我认为这个更好:lambda x: next(res if res &gt; 10 else 0 for res in (bar(x), )),原因是您避免了中间内存分配 @Netwave 我不认为中间 malloc 是相关的,即使它取决于函数,你也不会节省很多内存。

以上是关于我可以在保留 lambda 表达式的同时删除双重评估吗的主要内容,如果未能解决你的问题,请参考以下文章

使用 lambda 表达式时删除附加的事件处理程序 [重复]

使用正则表达式替换仅保留正斜杠和数字

如何返回带有守卫和双重递归的 lambda?

双重检查锁定模式 - 在传递给 call_once 的 lambda 中捕获

仅保留字符串中的有效字符

在 pyplot 子图中保留轴的同时删除框架