Python 会懒惰地评估 if 的条件吗? [复制]

Posted

技术标签:

【中文标题】Python 会懒惰地评估 if 的条件吗? [复制]【英文标题】:Does Python evaluate if's conditions lazily? [duplicate] 【发布时间】:2012-12-07 07:02:39 【问题描述】:

例如,如果我有以下语句:

if( foo1 or foo2)
    ...
    ...

如果 foo1 为真,python 会检查 foo2 的条件吗?

【问题讨论】:

见docs.python.org/2/reference/expressions.html#boolean-operations。 我常用的关键字提示,如果——像我一样——你懒得加载官方文档:在解释器控制台输入help("or")。在这种情况下,请阅读第四段。 Python 在这里的行为与“if”无关,与“or”有关。 有some modules that implement lazy evaluation in Python,可能就是你要找的。​​span> 从技术上讲,python 会短路,然后 双重评估布尔运算符的结果,如果以后使用实际的布尔值...除非它直接在if 语句 ... 是特权的(多于不是或 bool()),因此它对它们进行一次评估。双重评估取决于操作的复杂性。这是反直觉的,但这里有证据:gist.github.com/earonesty/08e9cbe083a5e0583feb8a34cc538010 【参考方案1】:

一个简短的演示是比较两者之间的时间差

all(xrange(1,1000000000))

any(xrange(1,1000000000))

all() 必须检查每一个值,而 any() 可以在找到第一个 True 后放弃。因此,作为生成器的 xrange 也会在评估器完成后立即放弃生成事物。出于这个原因,all 将消耗大量 RAM 并需要很长时间,而 any 将只使用几个字节并立即返回。

【讨论】:

【参考方案2】:

and or 很懒

& | 不偷懒

【讨论】:

【参考方案3】:

Python 的惰性可以通过以下代码证明:

def foo():
    print('foo')
    return False

def bar():
    print('bar')
    return False

foo() and bar()         #Only 'foo' is printed

另一方面,

foo() or bar()

会导致 'foo' 和 'bar' 都被打印出来。

【讨论】:

【参考方案4】:

确实是or部分短路了:

>>> 1 or 1/0  #also 0 and 1/0
1
>>> 0 or 1/0  #also 1 and 1/0

Traceback (most recent call last):
  File "<pyshell#1240>", line 1, in <module>
    0 or 1/0
ZeroDivisionError: integer division or modulo by zero

【讨论】:

【参考方案5】:

这在技术上不是惰性求值,而是短路布尔表达式。

懒惰的评估有一些不同的内涵。例如,真正的惰性评估可能会允许这样做

def foo(arg) :
    print "Couldn't care less"

foo([][0])

但 Python 没有。

Python 也很好,因为它“回声”它是布尔参数。例如,一个 or 条件返回它的第一个“真”参数或最后一个参数(如果所有参数都是“假的”)。与条件相反。

所以“回声参数”布尔意味着

2 和 [] 和 1

计算为 [],并且

[] 或 1 或 2

计算为 1

【讨论】:

惰性求值是一个包罗万象的术语,也可以指逻辑运算符的短路行为。如果您的意思是按需调用,则通常称为“按需调用”,因为惰性评估可能意味着很多。 我不同意。当他们的意思是“短路评估”时说“懒惰的评估”的人是错误的。 “按需调用”是“懒惰评估”的同义词。我同意它不太容易被滥用。 @PeteIsNeat 如果您想成为技术规范主义者,“惰性评估”是实现按需调用语义的众多方法之一。它们不是同义词,也不是等价的。我是一个描述主义者,所以当人们谈论“懒惰的行为”并且从上下文中很明显他们在谈论短路时,我并不介意。 :) 我是在谈话中引入“懒惰评估”的人。我只是想添加一些附加的上下文。如果您的意思是“短路评估”,那么说“惰性评估”是一种误导,我想确保每个人都理解这一点。至于“惰性评估”是否与“按需调用”同义……***page对我来说是正确的。 Wikipedia contradicts itself in this case:“延迟评估是按需调用语义最常用的实现策略,但也存在变体——例如乐观评估。” OP sorta-kinda 通过询问如何“懒惰地评估事物”在对话中引入了懒惰的评估。【参考方案6】:

是的,Python 会延迟计算,因此不会检查 foo2

如果我不知道密钥是否存在,我一直使用它来从类似字典的对象中获取项目:

if 'key' in mydict and mydict['key'] == 'heyyo!':
    do_stuff()

查看@unutbu 的回答以获得更完整的解释。

【讨论】:

对于那个用例,我认为if mydict.get("key") == 'heyyo!': 也可以工作——如果找不到密钥,.get 将返回None(或指定的默认值)。 正确,它会的,所以我一般不会将它用于实际的字典,而是用于没有.get 方法的类字典对象(通常来自外部模块)。跨度> @DSM 实际上,对于您的用例,我会简单地使用if mydict.get("key"):,因为None 将评估为False ?但是你会失去 'heyyo!' 比较。【参考方案7】:

是的,Python 懒惰地评估布尔条件。

docs say,

表达式 x 和 y 首先计算 x;如果 x 为假,则其值为 回来;否则,对 y 求值,结果值为 返回。

表达式 x 或 y 首先计算 x;如果 x 为真,则其值为 回来;否则,对 y 求值,结果值为 返回。

【讨论】:

我要指出,也可以进行按位比较,这不是懒惰的,例如下面的Eric Wang's answer。您也可以查看documentation。

以上是关于Python 会懒惰地评估 if 的条件吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如果 IF 语句不满足第一个条件,它会停止评估吗?

Haskell 不会懒惰地评估交错

Spark Transformation - 为啥它是懒惰的,有啥优势?

Python是不是检查多条件if语句中的所有条件? [复制]

懒惰地加载 NSTableView

带有if条件的隐式布尔评估[重复]