全部与与、任意与或

20 投票
2 回答
7359 浏览
提问于 2025-04-17 22:59

我想了解一下Python中的alland之间有什么区别,还有anyor之间的区别?比如:

status1 = 100
status2 = 300
status3 = 400

哪个用起来更好:

if status1 == 100 and status2 == 300 and status3 == 400:

或者

if all([status1 == 100, status2 == 300, status3 == 400]):

对于anyor的情况也是一样:

if status1 == 100 or status2 == 300 or status3 == 400:

或者

if any([status1 == 100, status2 == 300, status3 == 400]):

那么,使用内置函数和基本的orand条件,哪个更高效呢?

2 个回答

-1

总结

根据我的了解,当你需要比较多个布尔值(真或假)时,使用 all 更好,而当你只处理有限的布尔值时,使用 and 更合适。此外,使用 all 时,最好用生成器函数。

详细解释

编辑(为了更清楚地使用短路这个术语)

在有限的布尔表达式中,使用 and 是更好的选择,因为 Python 会在确定真假后立即停止评估每个布尔表达式。具体的例子和证明请见答案末尾。

由于只要有一个 False,由多个 and 组成的表达式就会返回 False,所以编译器会知道只需检查到第一个假值为止:

status1 == 100 and status2 == 300 and status3 == 400

比如它会检查 status1 == 100,如果这个结果是 False,它会立即停止处理这个表达式;如果是 True,它就会继续检查 status2 == 300,依此类推。

这种逻辑可以用循环来直观展示:

假设我们在编写 and 的逻辑,你会逐个检查每个表达式,看看它们是否都是 True,如果是就返回 True,如果找到一个 False,就返回 False。一旦遇到第一个假值,你就可以节省时间,立即退出。

def and(statements):
    for statement in statements:
        if not statement:
            return False
    return True

而对于 or,我们会编写逻辑,一旦找到一个 True 的表达式就退出,因为这证明了所有的 or 表达式对整个表达式的真假没有影响:

def or(statements):
    for statement in statements:
        if statement:
            return True
    return False

当然,当 andor 混合在一起时,这种逻辑会适当地遵循运算顺序。

andany 的表达式可以避免这种情况:

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 可能会有用。

对于 any 也有类似的论点:

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"

这会一直检查,直到找到一个满足条件的,因为之后的任何检查都不会改变这个表达式的真假。

** 编辑 ** 上述短路表达式的例子和证明。

考虑一下:

1 == 2 and 2 == 2

all([1 == 2, 2 == 2])

第一个表达式会将 1 == 2 评估为 False,整个表达式会立即短路,评估为 False。而第二个表达式会将 1 == 2 评估为 False2 == 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()

短路评估的效果在这里非常明显。你可以看到,即使如此,对于任何有限的布尔表达式,最好的方法仍然是使用明确的表达式,正如我在开头所说的。这些函数存在的场景是你可能不知道需要评估多少个布尔表达式。

26

在Python中,关键词 andor 遵循短路求值的规则。简单来说,就是当你用 andor 连接多个条件时,Python会根据情况决定是否继续检查后面的条件。如果前面的条件已经能决定结果,后面的条件就不会再被检查了。

allany 是函数,所以它们会检查所有的参数。也就是说,不管前面的条件是什么,后面的条件都会被计算。如果某些条件是函数调用,那么它们的表现可能会有所不同。

撰写回答