Python:any()/all()中的惰性函数求值 [英] Python: Lazy Function Evaluation in any() / all()

查看:74
本文介绍了Python:any()/all()中的惰性函数求值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Python中的逻辑运算符是惰性的.具有以下定义:

Logical operators in Python are lazy. With the following definition:

def func(s):
    print(s)
    return True

调用 or 运算符

>>> func('s') or func('t')
's'

仅求值第一个函数调用,因为 or 可以识别出该表达式求值为 True ,无论第二个函数调用的返回值如何.的行为类似.

only evaluates the first function call, because or recognizes that the expression evaluates to True, irregardless of the return value of the second function call. and does behave analogously.

但是,通过以下方式使用 any()(类似地: all())时:

However, when using any() (analogously: all()) in the following way:

>>> any([func('s'), func('t')])
's'
't'

所有函数调用都会被评估,因为在 any 开始迭代其项目的布尔值之前,首先构造内部列表.当我们省略列表构造并只写

all function calls are evaluated, because the inner list is constructed first, before any starts to iterate over the boolean values of its items. The same happens when we omit the list construction and just write

>>> any(func('s'), func('t'))
's'
't'

那样,我们就失去了 any 短路的能力,这意味着一旦iterable的第一个元素消失,它就会中断.如果函数调用的开销很大,那么预先评估所有函数将是一个巨大的损失,并且浪费了 any 的这种功能.从某种意义上讲,可以将其称为Python陷阱,因为对于试图利用 any 这一功能的用户而言,这可能是出乎意料的,并且因为通常认为 any 链接一系列 语句的另一种语法方式.但是 any 只是短路,而不是 lazy ,这是有区别的.

That way we lose the power of any being short-circuit, which means that it breaks as soon as the first element of the iterable is truish. If the function calls are expensive, evaluating all the functions up front is a big loss and is a waste of this ability of any. In some sense, one could call this a Python gotcha, because it might be unexpected for users trying to leverage this feature of any, and because any is often thought as being just another syntactic way of chaining a sequence of or statements. But any is just short-circuit, not lazy, and that is a difference here.

any 接受可迭代.因此,应该有一种创建迭代器的方法,该迭代器不会预先评估其元素,而是将未经评估的元素传递给 any ,并让它们仅按顺序在 any 内部进行评估以获得完全懒惰的评估.

any is accepting an iterable. So, there should be a way of creating an iterator which does not evaluate its elements up front but pass them unevaluated to any and lets them evaluate inside of any only, in order to achieve a fully lazy evaluation.

因此,问题是:我们如何才能将 any 用于真正的惰性函数评估?这意味着:如何在不预先评估所有函数调用的情况下,使任何可以使用的函数调用迭代器?

So, the question is: How can we use any with truly lazy function evaluation? That means: How can we make an iterator of function calls which any can consume, without evaluating all the function calls in advance?

推荐答案

我们可以使用 生成器表达式 ,分别传递函数及其参数,并仅在生成器中进行求值,如下所示:

We can use a generator expression, passing the functions and their arguments separately and evaluating only in the generator like so:

>>> any(func(arg) for arg in ('s', 't'))
's'

对于具有不同签名的不同功能,它可能类似于以下内容:

For different functions with different signatures, this could look like the following:

any(
    f(*args)
    for f, args in [(func1, ('s',)), (func2, (1, 't'))]
)

这样,一旦生成器中的一个函数调用评估为 True any 就会停止调用生成器中的 next()元素>,这意味着功能评估是完全惰性的.

That way, any will stop calling the next() element in the generator as soon as one function call in the generator evaluates to True, and that means that the function evaluation is fully lazy.

wjandrea 在评论中提到了另一种有效的函数评估方法:我们也可以使用lambda 表达式,像这样:

Another neat way to postpone the function evaluation was mentioned by wjandrea in a comment: We can also to use lambda expressions, like so:

>>> any(f() for f in [lambda: func('s'), lambda: func('t')]
's'

这篇关于Python:any()/all()中的惰性函数求值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆