Python支持短路吗?

453

Python支持布尔表达式的短路吗?


3个回答

432

是的,andor 运算符都支持短路计算 -- 请参见文档


266

运算符 andor 中的短路行为:

首先,让我们定义一个有用的函数来确定某些内容是否被执行。这是一个简单的函数,它接受一个参数,打印一条消息并返回输入(未更改)。

>>> def fun(i):
...     print "executed"
...     return i
... 

以下示例可以观察到Python中andor运算符的短路行为:Boolean-operations-and-or-not

>>> fun(1)
executed
1
>>> 1 or fun(1)    # due to short-circuiting  "executed" not printed
1
>>> 1 and fun(1)   # fun(1) called and "executed" printed 
executed
1
>>> 0 and fun(1)   # due to short-circuiting  "executed" not printed 
0

注意: 解释器认为以下数值表示假:

        False    None    0    ""    ()    []     {}

关于函数中的短路行为: any(), all():

Python的any()all()函数也支持短路行为。正如文档所示,它们按顺序评估序列的每个元素,直到找到允许提前退出的结果。请参考以下示例以了解两者。

any()函数检查是否有任何元素为True。只要遇到True就停止执行并返回True。

>>> any(fun(i) for i in [1, 2, 3, 4])   # bool(1) = True
executed
True
>>> any(fun(i) for i in [0, 2, 3, 4])   
executed                               # bool(0) = False
executed                               # bool(2) = True
True
>>> any(fun(i) for i in [0, 0, 3, 4])
executed
executed
executed
True

all()函数检查所有元素是否都为True,并在遇到False时停止执行:

>>> all(fun(i) for i in [0, 0, 3, 4])
executed
False
>>> all(fun(i) for i in [1, 0, 3, 4])
executed
executed
False

链式比较中的短路行为:

此外,在Python中,

比较可以任意链接,例如,x < y <= z等价于x < y and y <= z,但是当x < y为假时,y只被评估一次(但在这两种情况下,z都不会被评估)。

>>> 5 > 6 > fun(3)    # same as:  5 > 6 and 6 > fun(3)
False                 # 5 > 6 is False so fun() not called and "executed" NOT printed
>>> 5 < 6 > fun(3)    # 5 < 6 is True 
executed              # fun(3) called and "executed" printed
True
>>> 4 <= 6 > fun(7)   # 4 <= 6 is True  
executed              # fun(3) called and "executed" printed
False
>>> 5 < fun(6) < 3    # only prints "executed" once
executed
False
>>> 5 < fun(6) and fun(6) < 3 # prints "executed" twice, because the second part executes it again
executed
executed
False

编辑:
另一个有趣的要点是:Python中的逻辑and, or运算符返回操作数的,而不是布尔值(TrueFalse)。例如:

x为假时,运算x and y的结果为x,否则结果为y

与其他语言(如C中的&&||运算符)不同,它们返回0或1。

例如:

>>> 3 and 5    # Second operand evaluated and returned 
5                   
>>> 3  and ()
()
>>> () and 5   # Second operand NOT evaluated as first operand () is  false
()             # so first operand returned 
同样地,or运算符返回最左边的值,其bool(value)等于True,否则返回最右边的假值(根据短路行为),例如:
>>> 2 or 5    # left most operand bool(2) == True
2    
>>> 0 or 5    # bool(0) == False and bool(5) == True
5
>>> 0 or ()
()

那么这有什么用呢?在Magnus Lie Hetland所编写的Practical Python中给出了一个例子:
假设用户需要输入他或她的姓名,但可以选择不输入,如果没有输入,则希望使用默认值'<Unknown>'。你可以使用if语句,但你也可以非常简洁地表达:

In [171]: name = raw_input('Enter Name: ') or '<Unknown>'
Enter Name: 

In [172]: name
Out[172]: '<Unknown>'

换言之,如果从raw_input返回的值为真(非空字符串),则将其分配给名称(不会发生任何更改);否则,默认值'<Unknown>'被分配给name


4
小问题:显式列出的假值列表略有误导。任何类型都可以有一个或多个假值。按照惯例,所有数值类型的值为 0 的都是假值(所以不仅是 0,还包括 0.00jdecimal.Decimal(0)fractions.Fraction(0) 等),长度为 0 的所有集合也是假值(所以除了您列出的内容之外,b'' [Py3]、u'' [Py2] 和 set()/frozenset() 都是内置的可以计算为假值的内容),但用户定义/第三方类型可以定义自己的(通过直接使用 __bool__ [Py3]/__nonzero__ [Py2] 或间接地通过定义 __len__)。 - ShadowRanger
2
@ShadowRanger,你的评论将完善我的回答。感谢你添加这个注释。 - Grijesh Chauhan
另外,Python在计算短路条件时会进行两次求值,如果它们后来被用作布尔值...除非它们在if语句中,这是特权的:https://gist.github.com/earonesty/08e9cbe083a5e0583feb8a34cc538010 - Erik Aronesty
@GrijeshChauhan Python支持长电路吗? - Keerthana Prabhakaran
@KeerthanaPrabhakaran :( 抱歉,我不知道那个。如果您发布一个新问题,请与我分享。 - Grijesh Chauhan
显示剩余2条评论

63

是的。请在您的 Python 解释器中尝试以下内容:

and

>>>False and 3/0
False
>>>True and 3/0
ZeroDivisionError: integer division or modulo by zero
或者
>>>True or 3/0
True
>>>False or 3/0
ZeroDivisionError: integer division or modulo by zero

如何像 myVar == 5 and continue 这样做呢?它似乎是无效的。 - Royi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接