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 的条件吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
Spark Transformation - 为啥它是懒惰的,有啥优势?