2.6. and-or 的特殊性质

在Python中,and or 执行布尔逻辑,如你所期待的一样,但是它们并不返回布尔值;它们返回正在比较的真实值之一。

例 2.16. and 介绍

>>> 'a' and 'b'         1
'b'
>>> '' and 'b'          2
''
>>> 'a' and 'b' and 'c' 3
'c'
1 当使用 and,在一个布尔上下文中值的计算是从左向右进行的。0, '', [], (), {}, 和 None 在布尔上下文中是假;其它的所有东西都是真。[3] 如果在一个布尔上下文中所有的值都为真,and 返回最后一个值。在本例中,and 计算 'a',结果是真,接着是 'b',结果是真,则返回 'b'
2 如果在一个布尔上下文中有一个值为假,and 返回第一个假值。在本例中,'' 是第一个假值。
3 所有的值的真,所以 and 返回最后的值 'c'

例 2.17. or 介绍

>>> 'a' or 'b'          1
'a'
>>> '' or 'b'           2
'b'
>>> '' or [] or {}      3
{}
>>> def sidefx():
...     print "in sidefx()"
...     return 1
>>> 'a' or sidefx()     4
'a'
1 当使用 or 时,在一个布尔上下文中值的计算是从左到右进行的,就象 and。如果有一个值为真,or 立即返回那个值。在本例中,'a' 是第一个真值。
2 or 计算 '',结果为假,接着计算 'b',结果为真,则返回 'b'
3 如果所有的值为假,or 返回最后一个值。or 计算 '',结果为假,接着计算 [],结果为假,然后是 {},结果为假,则返回 {}
4 请注意在一个布尔上下文中,只有当找到一个真假时, or 才停止对值进行计算,然后它忽略其它的值。这一特性在某些值具有边际效应的时候很重要。这里,函数 sidefx 从未调用过,因为 or 计算 'a' 的结果为真,并且立即返回 'a'

如果你是一名C语言高手,当然对 bool ? a : b 表达式熟悉,这个表达式当 bool 为真时计算为 a,其它值则为 b。由于Python中 andor 的工作方式,你可以完成相同的事情。

例 2.18. and-or 技巧介绍

>>> a = "first"
>>> b = "second"
>>> 1 and a or b 1
'first'
>>> 0 and a or b 2
'second'
1

这个语法看起来与C语言中的 bool ? a : b 相似。整个表达式从左向右计算,所以 and 首先执行。1 and 'first' 计算为 'first',然后 'first' or 'second' 计算为 'first'

2 0 and 'first' 计算为 0,然后 0 or 'second' 计算为 'second'

然而,因为这个Python表达式是简单的布尔逻辑,而不是一个特殊的语言结构,所以在这个Python的 and-or 技巧与C中的 bool ? a : b 语法之间,有一个非常,非常,非常重要的不同。如果 a 的值为假,表达式将不会按你期望的那样执行。(你能知道我被这个问题折腾过吗?不只一次?)

例 2.19. 何时 and-or 技巧失败

>>> a = ""
>>> b = "second"
>>> 1 and a or b 1
'second'
1

因为 a 是一个空串,空串在一个布尔环境中被Python看成假值,1 and '' 计算为 '',然后 '' or 'second' 计算为 'second'。噢!这不是我们想要的。

Important
这个 and-or 技巧,bool and a or b,当 a 为假时,不会象C表达式 bool ? a : b 一样工作。

那么在 and-or 技巧之后的真正的技巧是确信 a 的值永远不为假。实现这一点的通常的方法之一是将 a 转化为 [a] 并且将 b 转化为 [b],接着使用返回的列表的第一个元素,应为 ab

例 2.20. 安全地使用 and-or 技巧

>>> a = ""
>>> b = "second"
>>> (1 and [a] or [b])[0] 1
''
1

因为 [a] 是一个非空列表,它永远不会为假。甚至 a0'' 或其它假值,列表 [a] 也为真,因为它有一个元素。

到现在为止,这个技巧可能看上去问题超过了它的价值。毕竟你可以用一个 if 语句完成相同的事情,那么为什么要经受这些麻烦呢?哦,在很多情况下,要在两个常量之间进行选择,所以可以使用更简单的语法而不必担心,因为你知道 a 值将总是真。并且尽管你不得不使用更复杂的安全形式,也有一些好的理由来使用这个技巧;在Python中有很多时候, if 语句不允许使用, 象 lambda 函数。

进一步阅读

脚注

[3] 好,几乎都在这儿了。缺省地,类的实例在一个布尔上下文中是真,但是你可以在你的类中定义特别的方法使得一个实例的计算为假。你将在第三章中学习所有关于类和特殊方法的内容。