面向非程序员的 Python 3 教程/布尔表达式
这里有一个布尔表达式的小例子(你不需要输入它)
a = 6
b = 7
c = 42
print(1, a == 6)
print(2, a == 7)
print(3, a == 6 and b == 7)
print(4, a == 7 and b == 7)
print(5, not a == 7 and b == 7)
print(6, a == 7 or b == 7)
print(7, a == 7 or b == 6)
print(8, not (a == 7 and b == 6))
print(9, not a == 7 and b == 6)
输出为
1 True 2 False 3 True 4 False 5 True 6 True 7 False 8 True 9 False
发生了什么?程序包含一些奇怪的print
语句。每个print
语句打印一个数字和一个表达式。数字是为了帮助跟踪我正在处理哪个语句。注意每个表达式最终都会变成False
或True
。在 Python 中,false 可以写成 0,true 可以写成 1。
这些行
print(1, a == 6)
print(2, a == 7)
分别打印一个True
和一个False
,正如预期的那样,因为第一个是 true,第二个是 false。第三个 print,print(3, a == 6 and b == 7)
,有点不同。运算符and
意味着如果前后两个语句都为真,那么整个表达式为真,否则整个表达式为假。下一行,print(4, a == 7 and b == 7)
,显示了如果and
表达式的部分为假,整个表达式就为假。and
的行为可以总结如下
表达式 | 结果 |
---|---|
true and true |
true |
true and false |
false |
false and true |
false |
false and false |
false |
请注意,如果第一个表达式为假,Python 不会检查第二个表达式,因为它知道整个表达式为假。尝试运行False and print("Hi")
并将它与运行True and print("Hi")
进行比较。这个技术术语叫做短路求值
下一行,print(5, not a == 7 and b == 7)
,使用了not
运算符。not
只是给出表达式的反面。(该表达式可以改写为 print(5, a != 7 and b == 7)
)。以下是表格
表达式 | 结果 |
---|---|
not true |
false |
not false |
true |
接下来的两行,print(6, a == 7 or b == 7)
和print(7, a == 7 or b == 6)
,使用了or
运算符。or
运算符如果第一个表达式为真,或者第二个表达式为真,或者两者都为真,则返回真。如果两者都不为真,则返回假。以下是表格
表达式 | 结果 |
---|---|
true or true |
true |
true or false |
true |
false or true |
true |
false or false |
false |
请注意,如果第一个表达式为真,Python 不会检查第二个表达式,因为它知道整个表达式为真。这是因为or
如果至少一半的表达式为真,则为真。第一部分为真,所以第二部分可以为假或真,但整个表达式仍然为真。
接下来的两行,print(8, not (a == 7 and b == 6))
和print(9, not a == 7 and b == 6)
,显示括号可以用来对表达式进行分组,并强制对一部分进行优先计算。请注意,括号将表达式从假变为真。这是因为括号迫使not
应用于整个表达式,而不是仅仅应用于a == 7
部分。
这里是一个使用布尔表达式的例子
list = ["Life", "The Universe", "Everything", "Jack", "Jill", "Life", "Jill"]
# make a copy of the list. See the More on Lists chapter to explain what [:] means.
copy = list[:]
# sort the copy
copy.sort()
prev = copy[0]
del copy[0]
count = 0
# go through the list searching for a match
while count < len(copy) and copy[count] != prev:
prev = copy[count]
count = count + 1
# If a match was not found then count can't be < len
# since the while loop continues while count is < len
# and no match is found
if count < len(copy):
print("First Match:", prev)
以下是输出
First Match: Jill
该程序通过持续检查匹配来工作,while count < len(copy) and copy[count] is not equal to prev
。当count
大于copy
的最后一个索引或找到匹配时,and
不再为真,因此循环退出。if
只是检查以确保while
退出是因为找到了匹配。
这个例子中也使用了and
的另一个“技巧”。如果你看看and
的表格,你会注意到第三个条目是“false and false”。如果count >= len(copy)
(换句话说,count < len(copy)
为假),那么copy[count]
永远不会被查看。这是因为 Python 知道如果第一个为假,那么它们不可能都为真。这被称为短路,如果您需要在第二个表达式会导致错误的情况下,则会非常有用。我使用第一个表达式 (count < len(copy)
) 来检查count
是否为copy
的有效索引。(如果你不相信我,请删除匹配的“Jill”和“Life”,检查它是否仍然有效,然后反转count < len(copy) and copy[count] != prev
的顺序,改为copy[count] != prev and count < len(copy)
。)
当您需要同时检查两个或多个不同的事情时,可以使用布尔表达式。
编程新手常犯的一个错误是误解了布尔运算符的工作方式,这源于 Python 解释器读取这些表达式的形式。例如,在最初学习了“and”和“or”语句之后,人们可能会认为表达式x == ('a' or 'b')
会检查变量x
是否等效于字符串'a'
或'b'
之一。事实并非如此。为了看到我正在说些什么,请使用解释器启动一个交互式会话,并输入以下表达式
>>> 'a' == ('a' or 'b') >>> 'b' == ('a' or 'b') >>> 'a' == ('a' and 'b') >>> 'b' == ('a' and 'b')
结果将是非直观的
>>> 'a' == ('a' or 'b') True >>> 'b' == ('a' or 'b') False >>> 'a' == ('a' and 'b') False >>> 'b' == ('a' and 'b') True
此时,and
和or
运算符似乎坏了。对于前两个表达式,'a'
等效于'a'
或'b'
,而'b'
则不是,这没有道理。此外,'b'
等效于'a'
和'b'
也没有道理。在检查了解释器对布尔运算符的操作之后,这些结果实际上完全符合您的要求,只是它不像您认为的那样。
当 Python 解释器查看一个or
表达式时,它会取第一个语句并检查它是否为真。如果第一个语句为真,那么 Python 会返回该对象的返回值,而不会检查第二个语句。这是因为对于or
表达式,如果其中一个值为真,那么整个表达式都为真;程序不需要理会第二个语句。另一方面,如果第一个值被评估为假,那么 Python 会检查第二部分并返回该值。第二部分决定了整个表达式的真值,因为第一部分是假的。这种解释器中的“懒惰”称为“短路”,是许多编程语言中评估布尔表达式的常用方式。
类似地,对于and
表达式,Python 使用短路技术来加速真值评估。如果第一个语句为假,那么整个语句必须为假,因此它返回该值。否则,如果第一个值为真,它会检查第二个并返回该值。
需要说明的是,布尔表达式返回一个表示True
或False
的值,但 Python 认为许多不同的东西都具有真值。要检查任何给定对象x
的真值,可以使用函数bool(x)
查看其真值。以下是一些对象的真值示例
True | False |
---|---|
True | False |
1 | 0 |
非零数字 | 字符串 'None' |
非空字符串 | 空字符串 |
非空列表 | 空列表 |
非空字典 | 空字典 |
现在我们可以理解我们在之前测试那些布尔表达式时得到的令人困惑的结果。让我们看看解释器在处理代码时“看到了”什么
第一种情况
>>> 'a' == ('a' or 'b') # Look at parentheses first, so evaluate expression "('a' or 'b')" # 'a' is a nonempty string, so the first value is True # Return that first value: 'a' >>> 'a' == 'a' # the string 'a' is equivalent to the string 'a', so expression is True True
第二种情况
>>> 'b' == ('a' or 'b') # Look at parentheses first, so evaluate expression "('a' or 'b')" # 'a' is a nonempty string, so the first value is True # Return that first value: 'a' >>> 'b' == 'a' # the string 'b' is not equivalent to the string 'a', so expression is False False
第三种情况
>>> 'a' == ('a' and 'b') # Look at parentheses first, so evaluate expression "('a' and 'b')" # 'a' is a nonempty string, so the first value is True, examine second value # 'b' is a nonempty string, so second value is True # Return that second value as result of whole expression: 'b' >>> 'a' == 'b' # the string 'a' is not equivalent to the string 'b', so expression is False False
第四种情况
>>> 'b' == ('a' and 'b') # Look at parentheses first, so evaluate expression "('a' and 'b')" # 'a' is a nonempty string, so the first value is True, examine second value # 'b' is a nonempty string, so second value is True # Return that second value as result of whole expression: 'b' >>> 'b' == 'b' # the string 'b' is equivalent to the string 'b', so expression is True True
因此,当 Python 给出那些明显错误的结果时,它实际上是在执行它的工作。如前所述,重要的是要识别布尔表达式在评估时将返回什么值,因为它并不总是很明显。
回到最初的表达式,以下是如何编写它们,以使其按您希望的方式执行
>>> 'a' == 'a' or 'a' == 'b' True >>> 'b' == 'a' or 'b' == 'b' True >>> 'a' == 'a' and 'a' == 'b' False >>> 'b' == 'a' and 'b' == 'b' False
当这些比较被评估时,它们会以 True 或 False 的形式返回真值,而不是字符串,所以我们会得到正确的结果。
password1.py
## This program asks a user for a name and a password.
# It then checks them to make sure that the user is allowed in.
name = input("What is your name? ")
password = input("What is the password? ")
if name == "Josh" and password == "Friday":
print("Welcome Josh")
elif name == "Fred" and password == "Rock":
print("Welcome Fred")
else:
print("I don't know you.")
示例运行
What is your name? Josh What is the password? Friday Welcome Josh
What is your name? Bill What is the password? Money I don't know you.
编写一个程序,让用户猜您的名字,但他们只有 3 次机会,否则程序将退出。
print("Try to guess my name!")
count = 1
name = "guilherme"
guess = input("What is my name? ")
while count < 3 and guess.lower() != name: # .lower allows things like Guilherme to still match
print("You are wrong!")
guess = input("What is my name? ")
count = count + 1
if guess.lower() != name:
print("You are wrong!") # this message isn't printed in the third chance, so we print it now
print("You ran out of chances.")
else:
print("Yes! My name is", name + "!")