跳转到内容

面向非程序员的 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语句打印一个数字和一个表达式。数字是为了帮助跟踪我正在处理哪个语句。注意每个表达式最终都会变成FalseTrue。在 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

此时,andor运算符似乎坏了。对于前两个表达式,'a' 等效于'a''b',而'b' 则不是,这没有道理。此外,'b' 等效于'a''b' 也没有道理。在检查了解释器对布尔运算符的操作之后,这些结果实际上完全符合您的要求,只是它不像您认为的那样。

当 Python 解释器查看一个or表达式时,它会取第一个语句并检查它是否为真。如果第一个语句为真,那么 Python 会返回该对象的返回值,而不会检查第二个语句。这是因为对于or表达式,如果其中一个值为真,那么整个表达式都为真;程序不需要理会第二个语句。另一方面,如果第一个值被评估为假,那么 Python 会检查第二部分并返回该值。第二部分决定了整个表达式的真值,因为第一部分是假的。这种解释器中的“懒惰”称为“短路”,是许多编程语言中评估布尔表达式的常用方式。

类似地,对于and表达式,Python 使用短路技术来加速真值评估。如果第一个语句为假,那么整个语句必须为假,因此它返回该值。否则,如果第一个值为真,它会检查第二个并返回该值。

需要说明的是,布尔表达式返回一个表示TrueFalse的值,但 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 + "!")


面向非程序员的 Python 3 教程
 ← For 循环 布尔表达式 字典 → 
华夏公益教科书