3.7 Python 布尔表达式用作控制结构*
有了顺序、分支和循环控制结构,原则上已足以表达所有算法。然而,为了在解决某些问题时编程更加方便,各种语言还提供了若干其他控制结构。本节介绍 Python 的一个特色, 即布尔表达式可当作控制结构来用。
编程语言中的表达式本来只是用来产生值的,布尔表达式也不例外。布尔表达式的常规 用法是计算产生 True 或 False,并用在分支和循环控制结构当中。但 Python 中的布尔表达式 还可以用作控制结构,这是由 Python 在底层计算布尔表达式时所采用的计算策略决定的。为了理解布尔表达式如何用作控制结构,需要了解 Python 是如何实现布尔运算的,详情见第 2章。
考虑用一个交互式循环来实现“yes or no”功能:程序询问用户一个问题,用户输入回 答。只要用户输入的字符串以“y”或者”Y”开头,就算该用户回答是 yes,程序再进行合适的 处理;否则就跳过处理过程。这个功能很容易用 while 循环语句实现:
answer = raw_input("Want to play?(yes or no) ")
while answer[0] == "y" or answer[0] == "Y":
play()
answer = raw_input("Want to play?(yes or no) ")
显然这里 while 语句中的条件表达式等同于自然语言中的“用户输入以 y 打头或者用户 输入以 Y 打头”。然而,自然语言一般不会这么罗嗦,更简洁的表达是“用户输入以 y 或 Y 打头”。可惜这种简明的表达在编程语言中常常是错误的,初学编程者受自然语言的影响,很 容易写出下面这样的布尔表达式:
while answer[0] == "y" or "Y":
上面这个布尔表达式的写法在大多数语言中都导致语法错误,因此能够被编译器或解释器发 现,不会造成严重后果。但是在 Python 中,这个表达式的语法却完全没有问题。然而,它的 语义却很有问题,事实上,这个布尔表达式会导致一个无穷循环!原因就在于 Python 在底层 实现布尔运算时所采取的“捷径”策略。
我们来看表达式 answer[0] == “y” or “Y”的计算。布尔运算符 or 所连接的两个表达式分别 是 answer[0] == “y”和”Y”,左边的表达式是真正的布尔表达式,计算结果为 True 或 False;而 右边的表达式是一个字符串,它的值就是固定的非空串”Y”。根据第 2 章中介绍的 Python 对 运算符 or 的计算规则:若 answer[0] == “y”计算到 True,则整个布尔表达式的值就是 True, 不去考虑右边的表达式;若 answer[0] == “y”计算到 False,则整个布尔表达式返回值”Y”,这 个非空串被 Python 视为 True。总之,不管用户输入的是什么,表达式 answer[0] == “y” or “Y” 永远为真,亦即 while 循环是无穷循环。
Python 的这个特性对初学者来说是个潜在的陷阱,很容易犯错误。当然,Python 之所以 如此设计,也有它的理由,那就是布尔表达式可以用作控制结构,在某些情况下可以写出更 简明的代码。例如考虑这种需求:程序要求用户输入一个字符串,如果用户没有输入数据就 直接按了回车键,则程序采用缺省值”Python”。实现这种需求的代码如下:
ans = raw_input("What's your favorite? [Python] ")
if s != "":
favorite = ans
else:
favorite = "Python"
利用字符串可被 Python 解释为布尔值的特性,上面代码中 if 语句的条件可以简化成:
ans = raw_input("What's your favorite? [Python] ")
if ans:
favorite = ans
else:
favorite = "Python"
当用户直接按回车,则 ans 为空串,并被 Python 解释为 False,从而 favorite 被赋值为缺省值”Python”。再利用布尔运算 or 的计算捷径规则,代码可以进一步简化为:
ans = raw_input("What's your favorite? [Python] ")
favorite = ans or "Python"
根据 or 的计算规则,此处第二行语句中的 ans or “Python”等同于一个 if-else 结构,即:若 ans 非空,就直接返回它的值;若 ans 为空串,则返回”Python”。这就是我们所说的“布尔表达式 用作流程控制结构”。
顺便说一下,如果考虑到 ans 其实就是函数 raw_input 的返回值,这个例子最终可以精简 成一行代码:
favorite = raw_input("What's your favorite? [Python] ") or "Python"
与上面第一个版本(5 行代码)相比,显然代码量大大减少了。看上去似乎不错,但其实程 序的可读性也大大降低了,因为最后这个一行语句的版本对初学者来说是很难理解的。从良 好编程风格的角度说,宁可多写几条语句,也要保证程序的可读性和以理解性。