跳轉到內容

面向非程式設計師的 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 迴圈 布林表示式 字典 → 
華夏公益教科書