tl;dr
据我所知,all 更适合用于比较不同数量的布尔语句,and 更适合有限布尔语句,而使用all 时,请尝试使用生成器函数。
详细解释
编辑(为了清楚地使用术语短路)
它们在有限语句中的使用是首选,因为一旦可以确定真相,Python 将缩短每个布尔语句的评估。 有关证明和详细示例,请参见答案末尾。
由于任何由连续的and 语句组成的语句都将是False,如果至少有一个语句是False,那么编译器知道只检查直到它得到一个错误的答案:
status1 == 100 and status2 == 300 and status3 == 400
如果发现是False,它将检查status1 == 100,如果是True,它将立即停止处理该语句,如果现在将检查status2 == 300,等等。
这种逻辑可以用循环直观地展示:
我们正在为 and 语句编写行为的图像,您将检查沿线的每个语句并确定它们是否都是 True 并返回 True 或者我们会找到 False 值并返回 @987654338 @。您可以在达到第一个虚假陈述后节省时间并立即退出。
def and(statements):
for statement in statements:
if not statement:
return False
return True
对于or,我们将编写一旦找到True 语句就会退出的逻辑,因为这证明所有或语句与整个语句的整体真实性无关:
def or(statements):
for statement in statements:
if statement:
return True
return False
当and 和or 语句混合在一起时,这个逻辑当然是按照操作顺序适当地混合和交织在一起的
and 和 any 语句用于避免这种情况:
collection_of_numbers = [100,200,300,400,500,600,.....]
if collection_of_numbers[0] == 100 and collection_of_numbers[1] == 200 and .......:
print "All these numbers make up a linear set with slope 100"
else:
print "There was a break in the pattern!!!"
与or类似
collection_of_numbers = [100,200,300,400,500,600,.....]
if collection_of_numbers[0] == 100 or collection_of_numbers[1] == 200 or .......:
print "One of these numbers was a multiple of 100"
else:
print "None of these numbers were multiples of 100"
例如:
temp = []
itr = 0
for i in collection_of_numbers:
temp.append(i == itr)
itr += 100
if all(temp):
print "The numbers in our collection represent a linear set with slope 100"
else:
print "The numbers in out collection do not represent a linear set with slope 100"
一个愚蠢的例子,但我认为它展示了all 可能有用的场景类型。
类似的论点适用于任何:
temp = []
for i in collection_of_numbers:
temp.append(i%3 == 0)
if any(temp):
print "There was at least one number in our collect that was divisible by three"
else:
print "There were no numbers in our collection divisible by three"
尽管有人认为使用循环实现这种逻辑可以节省更多时间。
为and 而不是all:
itr = 0
result = True
for i in collection_of_numbers:
if not i == itr:
result = False
break
itr += 100
if result:
print "The numbers in our collection represent a linear set with slope 100"
else:
print "The numbers in out collection do not represent a linear set with slope 100"
不同之处在于这会在检查每个条目之前中断,从而在早期条目破坏您的条件的大型集合中节省大量时间。
对于or 而不是any:
temp = []
result = False
for i in collection_of_numbers:
if i%3 == 0:
result = True
break
if result:
print "There was at least one number in our collect that was divisible by three"
else:
print "There were no numbers in our collection divisible by three"
这将检查直到找到满足条件的任何内容,因为之后的任何内容都不会改变 True 语句的方式。
** 编辑 ** 上述使用短路措辞和声明证明的示例。
考虑
1 == 2 and 2 == 2
和
all([1 == 2, 2 == 2])
第一个语句会将1 == 2 评估为False,整个语句将立即短路并评估为False。而第二个语句将评估1 == 2 为False,2 == 2 为True,然后在输入函数and 时它现在将返回False。必须首先评估每个语句的额外步骤是为什么如果您检查一些小情况有限的布尔检查集而不使用该函数是可取的。
虽然与两个语句无关紧要,但如果你举一个极端的例子,你会明白我所说的所有布尔语句的评估都是短路的。下面的测试以不同的方式评估 1000 布尔语句并计算它们的执行时间。每个语句的第一个布尔语句都会导致整个布尔语句发生短路,但不会导致求值。
test.py
import timeit
explicit_and_test = "1 == 0 and " + " and ".join(str(i) + " == " + str(i) for i in range(1000))
t = timeit.Timer(explicit_and_test)
print t.timeit()
function_and_test = "all([1 == 0, " + ", ".join(str(i) + " == " + str(i) for i in range(1000)) + "])"
t = timeit.Timer(function_and_test)
print t.timeit()
setup = """def test_gen(n):
yield 1 == 0
for i in xrange(1,n):
yield i == i"""
generator_and_test = "all(i for i in test_gen(1000))"
t = timeit.Timer(generator_and_test,setup=setup)
print t.timeit()
运行时:
$ python test.py
0.0311999320984 # explicit and statement
26.3016459942 # List of statements using all()
0.795602083206 # Generator using all()
语句的短路评估的影响在这里通过一个过高的因素显而易见。您可以看到,对于任何类型的有限布尔语句,最好的方法仍然是使用显式语句,正如我在冗长答案的开头所说的那样。这些函数适用于您可能不知道需要评估多少个布尔语句的情况。