【问题标题】:all vs and AND any vs or全部 vs 和 AND 任何 vs 或
【发布时间】:2014-04-25 22:54:13
【问题描述】:

我很想知道两者有什么区别

all and "and"
any and "or"

例如: 状态1=100,状态2=300,状态3=400

哪个更好用:

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

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

对于任何和或条件类似:

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

哪个更有效,使用内置函数还是原始的 or 和 and 条件?

【问题讨论】:

  • 如果你这样做all([status1==100,status2==300,status3=400]),它首先必须创建整个列表,所以我猜and 更好。不过,生成器可能会有所不同。
  • 当然可以timeit,但我认为使用逻辑运算符总是比构造新的列表对象并调用函数更快。

标签: python


【解决方案1】:

关键字andor 遵循Python 的short circuit evaluation 规则。由于allany 是函数,所有参数都将被计算。如果某些条件是函数调用,则可能会获得不同的行为。

【讨论】:

  • 这是一个扎实而简单的答案,直截了当。如果您只需要一个if 语句并且您手头有变量,那么使用any/all 可能是错误的选择。 any/all 旨在针对谓词函数列表使用。它们在函数式编程中很受欢迎。考虑if any(isOdd(x) for x in data)。在这里,您有来自某个地方的数据,您想对此做出决定。
  • anyall 的所有参数都将被计算,但它们的 真值 可能不会被计算,因为这些函数也是短路的 - 试试 any(1 / i for i in [1, 0])
  • 如果您不想“尝试”,则上述计算结果为 True。事实上 1/0 没有被评估,因为 1/1 已经是 True。交换 1 和 0 的顺序,它就会退缩。
【解决方案2】:

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

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 可能有用的场景类型。

类似的论点适用于任何:

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 == 2False2 == 2True,然后在输入函数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()

语句的短路评估的影响在这里通过一个过高的因素显而易见。您可以看到,对于任何类型的有限布尔语句,最好的方法仍然是使用显式语句,正如我在冗长答案的开头所说的那样。这些函数适用于您可能不知道需要评估多少个布尔语句的情况。

【讨论】:

  • 您的 any() 示例效率非常低 - 为什么不使用生成器理解?实际上,使用三元运算符,您可以将其压缩为单行:print 'foo' if any(i%3 == 0 for i in collection_of_numbers) else 'bar'
  • @AirThomas 虽然你是对的,但正如我所提到的,它们是用于明确说明 anyall 正在做什么的愚蠢示例,即对一组 booleans 进行评估。没有任何快捷方式。我的回答是为了明确和明显的细节(可能以牺牲效率为代价),因为这个问题归结为理解这两个内置命令的作用,以便能够将它们的功能与显式布尔语句进行比较.
  • 感谢您在此答案中投入的时间和精力,但您的前提是错误的; anyallguaranteed to be equivalent to the functions you rewrote as and and or,表示 they really do short-circuit。为了明确说明这些函数在做什么,您需要发布较低级别的源代码。
  • @AirThomas 我不相信我说他们不遵循短路评估?我编写了两个函数 andor 是为了让 OP 深入了解这些函数的工作原理。我不认为我的前提 (all is better to use when you may be comparing a varying amount of boolean statments and using and is much better for a finite boolean statement.) 是错误的,我很想知道你为什么这么认为?
  • 我指的是:“他们的 [and's] 在有限语句中的用法是首选,因为一旦可以确定真相,Python 就会短路语句。”
猜你喜欢
  • 2016-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
相关资源
最近更新 更多